diff options
Diffstat (limited to 'source/libmaple')
29 files changed, 1181 insertions, 0 deletions
diff --git a/source/libmaple/api/adc.rst b/source/libmaple/api/adc.rst new file mode 100644 index 0000000..8817055 --- /dev/null +++ b/source/libmaple/api/adc.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-adc: + +``adc.h`` +========= + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: adc.h diff --git a/source/libmaple/api/bitband.rst b/source/libmaple/api/bitband.rst new file mode 100644 index 0000000..fd57944 --- /dev/null +++ b/source/libmaple/api/bitband.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-bitband: + +``bitband.h`` +============= + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: bitband.h diff --git a/source/libmaple/api/bkp.rst b/source/libmaple/api/bkp.rst new file mode 100644 index 0000000..9a697c7 --- /dev/null +++ b/source/libmaple/api/bkp.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-bkp: + +``bkp.h`` +========= + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: bkp.h diff --git a/source/libmaple/api/dac.rst b/source/libmaple/api/dac.rst new file mode 100644 index 0000000..038753b --- /dev/null +++ b/source/libmaple/api/dac.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-dac: + +``dac.h`` +========= + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: dac.h diff --git a/source/libmaple/api/delay.rst b/source/libmaple/api/delay.rst new file mode 100644 index 0000000..a0d013a --- /dev/null +++ b/source/libmaple/api/delay.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-delay: + +``delay.h`` +=========== + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: delay.h diff --git a/source/libmaple/api/dma.rst b/source/libmaple/api/dma.rst new file mode 100644 index 0000000..1512d0c --- /dev/null +++ b/source/libmaple/api/dma.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-dma: + +``dma.h`` +========= + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: dma.h diff --git a/source/libmaple/api/exti.rst b/source/libmaple/api/exti.rst new file mode 100644 index 0000000..2909aa7 --- /dev/null +++ b/source/libmaple/api/exti.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-exti: + +``exti.h`` +========== + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: exti.h diff --git a/source/libmaple/api/flash.rst b/source/libmaple/api/flash.rst new file mode 100644 index 0000000..6f2f9d3 --- /dev/null +++ b/source/libmaple/api/flash.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-flash: + +``flash.h`` +=========== + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: flash.h diff --git a/source/libmaple/api/fsmc.rst b/source/libmaple/api/fsmc.rst new file mode 100644 index 0000000..cecfc99 --- /dev/null +++ b/source/libmaple/api/fsmc.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-fsmc: + +``fsmc.h`` +========== + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: fsmc.h diff --git a/source/libmaple/api/gpio.rst b/source/libmaple/api/gpio.rst new file mode 100644 index 0000000..2cfec23 --- /dev/null +++ b/source/libmaple/api/gpio.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-gpio: + +``gpio.h`` +========== + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: gpio.h diff --git a/source/libmaple/api/i2c.rst b/source/libmaple/api/i2c.rst new file mode 100644 index 0000000..14dd304 --- /dev/null +++ b/source/libmaple/api/i2c.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-i2c: + +``i2c.h`` +========= + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: i2c.h diff --git a/source/libmaple/api/iwdg.rst b/source/libmaple/api/iwdg.rst new file mode 100644 index 0000000..3911ece --- /dev/null +++ b/source/libmaple/api/iwdg.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-iwdg: + +``iwdg.h`` +========== + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: iwdg.h diff --git a/source/libmaple/api/libmaple.rst b/source/libmaple/api/libmaple.rst new file mode 100644 index 0000000..d4f28f0 --- /dev/null +++ b/source/libmaple/api/libmaple.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-libmaple: + +``libmaple.h`` +============== + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: libmaple.h diff --git a/source/libmaple/api/libmaple_types.rst b/source/libmaple/api/libmaple_types.rst new file mode 100644 index 0000000..bbea2c1 --- /dev/null +++ b/source/libmaple/api/libmaple_types.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-libmaple_types: + +``libmaple_types.h`` +==================== + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: libmaple_types.h diff --git a/source/libmaple/api/nvic.rst b/source/libmaple/api/nvic.rst new file mode 100644 index 0000000..b94dc31 --- /dev/null +++ b/source/libmaple/api/nvic.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-nvic: + +``nvic.h`` +========== + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: nvic.h diff --git a/source/libmaple/api/pwr.rst b/source/libmaple/api/pwr.rst new file mode 100644 index 0000000..82e4864 --- /dev/null +++ b/source/libmaple/api/pwr.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-pwr: + +``pwr.h`` +========= + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: pwr.h diff --git a/source/libmaple/api/rcc.rst b/source/libmaple/api/rcc.rst new file mode 100644 index 0000000..81dc604 --- /dev/null +++ b/source/libmaple/api/rcc.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-rcc: + +``rcc.h`` +========= + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: rcc.h diff --git a/source/libmaple/api/ring_buffer.rst b/source/libmaple/api/ring_buffer.rst new file mode 100644 index 0000000..a014fa4 --- /dev/null +++ b/source/libmaple/api/ring_buffer.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-ring_buffer: + +``ring_buffer.h`` +================= + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: ring_buffer.h diff --git a/source/libmaple/api/scb.rst b/source/libmaple/api/scb.rst new file mode 100644 index 0000000..78cc7eb --- /dev/null +++ b/source/libmaple/api/scb.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-scb: + +``scb.h`` +========= + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: scb.h diff --git a/source/libmaple/api/spi.rst b/source/libmaple/api/spi.rst new file mode 100644 index 0000000..b0c7e86 --- /dev/null +++ b/source/libmaple/api/spi.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-spi: + +``spi.h`` +========= + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: spi.h diff --git a/source/libmaple/api/stm32.rst b/source/libmaple/api/stm32.rst new file mode 100644 index 0000000..2784540 --- /dev/null +++ b/source/libmaple/api/stm32.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-stm32: + +``stm32.h`` +=========== + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: stm32.h diff --git a/source/libmaple/api/systick.rst b/source/libmaple/api/systick.rst new file mode 100644 index 0000000..5ec906c --- /dev/null +++ b/source/libmaple/api/systick.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-systick: + +``systick.h`` +============= + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: systick.h diff --git a/source/libmaple/api/timer.rst b/source/libmaple/api/timer.rst new file mode 100644 index 0000000..3acbf4f --- /dev/null +++ b/source/libmaple/api/timer.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-timer: + +``timer.h`` +=========== + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: timer.h diff --git a/source/libmaple/api/usart.rst b/source/libmaple/api/usart.rst new file mode 100644 index 0000000..26e6b9c --- /dev/null +++ b/source/libmaple/api/usart.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-usart: + +``usart.h`` +=========== + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: usart.h diff --git a/source/libmaple/api/util.rst b/source/libmaple/api/util.rst new file mode 100644 index 0000000..50ffe76 --- /dev/null +++ b/source/libmaple/api/util.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-util: + +``util.h`` +========== + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: util.h diff --git a/source/libmaple/apis.rst b/source/libmaple/apis.rst new file mode 100644 index 0000000..f493406 --- /dev/null +++ b/source/libmaple/apis.rst @@ -0,0 +1,14 @@ +.. _libmaple-apis: + +APIs +==== + +This is the master index for libmaple proper's APIs. + +**Contents** + +.. toctree:: + :maxdepth: 1 + :glob: + + api/* diff --git a/source/libmaple/coding-standard.rst b/source/libmaple/coding-standard.rst new file mode 100644 index 0000000..23d20f8 --- /dev/null +++ b/source/libmaple/coding-standard.rst @@ -0,0 +1,412 @@ +.. _libmaple-coding-standard: + +Coding Standard +=============== + +This page documents the coding standard for :ref:`libmaple`. It's +intended as a guide for how you should structure any code you would +like included into the LeafLabs releases of libmaple. + +LeafLabs team members are required to follow these when producing new +code. Community contributors to libmaple are strongly encouraged to +do so; following these rules will greatly increase the probability +that your patches will be folded in. + +In general, follow this guide unless there's a very good reason not +to. Laziness doesn't count as a good reason. Most, if not all, of +these decisions are entirely arbitrary, but it's important for +readability that we be consistent. (If you notice an inconsistency, +you should fix it). + +Note that the file ``.dir-locals.el`` in the libmaple root directory +already ensures that many of these standards are followed by default +in Emacs (but not on Windows, where it would need to be named +``_dir_locals.el``, and no way, man). There's also some elisp +scattered about this file which will provide you additional help. + +Vim customizations to do the same thing would be nice! + +.. contents:: Contents + :local: + +License +------- + +.. highlight:: scheme + +Put an MIT license at the beginning of the file (look at any of our +source files for an example). Copyright should go either to you or to +LeafLabs, LLC. + +Emacs: if you don't like seeing the license, you should use elide-head +(which will hide it for you). You can use the following:: + + (require 'elide-head) + (setq programming-mode-hooks '(c-mode-hook c++-mode-hook)) + (add-to-list 'elide-head-headers-to-hide + '("The MIT License" . "DEALINGS IN\n [*] THE SOFTWARE")) + (add-to-list 'elide-head-headers-to-hide + '("The MIT License" . "DEALINGS IN THE\n...SOFTWARE")) + (dolist (hook programming-mode-hooks) + (add-hook hook (lambda () (elide-head)))) + +Whitespace +---------- + +- 4 space indents (set in ``.dir-locals.el``). + +- Unix newlines. Some exceptions are currently grandfathered in; these + will go away in time. + +- No tab characters (set in ``.dir-locals.el``). + +- No trailing whitespace. For help getting this (and no tab + characters) done automatically in Emacs, you can use + `code-fascism.el <https://github.com/mbolivar/code-fascism>`_. + +- Files end in exactly one newline. The presence of a newline at EOF + is already done by ``c-require-final-newline`` in recent versions of + Emacs. + +- Exactly two newlines separate source paragraphs (you do separate + your code into paragraphs, don't you?). + +- The first line in a function is non-blank. + +.. highlight:: cpp + +- Exactly one space after ``if``, ``else``, ``for``, and ``while``, + before the following ``{`` or ``(``. One space before ``else``, + after the preceding ``}``. For example:: + + // This is good; we like this: + if (foo) { + while (quux) { + bar(); + } + } else { + baz(); + } + + // THIS IS BAD! DON'T DO THIS: + if(foo){ + while(quux){ + bar(); + } + }else{ + baz(); + } + +- Exactly one space in between binary arithmetic, logical, and + comparison operators and their operands. Examples:: + + // This is good: + int x = a + b * (c - d); + if (x != 0 && a > 7) { + SerialUSB.println(x); + } + + // THIS IS BAD! + int x = a+b*(c-d); + if (x!=0 && a>7) { + SerialUSB.println(x); + } + + // This is good: + uint32 adc_data = ADC1_BASE->DR; + SerialUSB.println(adc_data); + + // THIS IS BAD! + uint32 adc_data = ADC1_BASE -> DR; + SerialUSB . println(adc_data); + +- No space between a unary operator and its operand. Examples:: + + // Good: + x++; + + // BAD! + x ++; + + // Good: + y = -x; + + // BAD! + y = - x; + +- If you need to break up a long line: + + * Prefer to break up long expressions after a binary operator. Example:: + + // Good: + if (some_really_long_conditional_wow_this_really_goes_on_forever || + maybe_something_else_could_happen_too) { + ... + } + + // BAD! + if (some_really_long_conditional_wow_this_really_goes_on_forever + || maybe_something_else_could_happen_too) { + ... + } + + * When breaking up a function's arguments over multiple lines, align + the arguments on subsequent lines with the first argument. + Example:: + + // Good: + return_type value_i_got = function_with_a_really_long_name(argument1, + argument2, + argument3); + + // BAD! + return_type value_i_got = function_with_a_really_long_name(argument1, + argument2, + argument3); + + // BAD! + return_type value_i_got = function_with_a_really_long_name(argument1, + argument2, + argument3); + +- In function invocations, no space in between the function name and + the opening parenthesis. Example:: + + // Good: + SerialUSB.println("Hello, world!"); + + // BAD! + SerialUSB.println ("Hello, world!"); + +- Don't indent C code within a conditionally-compiled ``extern "C"`` + block. Example:: + + // Good: + #ifdef __cplusplus + extern "C"{ + #endif + + void some_c_function(void); + + #ifdef __cplusplus + } // extern "C" + #endif + + // BAD! + #ifdef __cplusplus + extern "C"{ + #endif + + void some_c_function(void); + + #ifdef __cplusplus + } // extern "C" + #endif + + Emacs does the "bad" behavior by default, which can be very + annoying. You can turn this off with :: + + (defun c-mode-inextern-lang-hook () + (setcdr (assq 'inextern-lang c-offsets-alist) '-)) + (add-hook 'c-mode-hook c-mode-inextern-lang-hook) + +Comments +-------- + +.. highlight:: c++ + +- Multi-line comments are pretty flexible. Any of these is fine:: + + /* Comment starts here. + * Continued lines have a '*' before them. + * The comment can end after the last line. + */ + + /* Comment starts here. + * The comment can end on the same line. */ + + /* + * You can also place a newline after the opening "/*". + */ + +- Doxygen comments are multi-line comments that begin with ``/**`` + instead. + +- Single-line comments are up to you. + +Braces +------ + +- Mostly `1TBS + <http://en.wikipedia.org/wiki/Indent_style#Variant:_1TBS>`_. The + only difference is that the opening brace of a function's definition + occurs exactly one space character after the closing parenthesis in + that function's parameter list. Example:: + + void func(void) { + ... + } + +Naming conventions +------------------ + +We'll handle the usual casing/underscore debate as follows. + +- First, ``Dont_Mix_Like_This``, because ``It_Looks_Really_Ugly``, ok? + [There's been some debate about this, and some exceptions are + already grandfathered in, so in order to settle it, let's call this + a "recommendation" instead of "requirement".] + +- Variables: Use underscores to separate words in C identifiers:: + + int some_example_name; + + User-facing C++ variables should be camel cased + (``thisIsAnExample``, ``boardPWMPins``, etc.), for consistency with + the Arduino style. It's probably a good idea for you to case + non-user facing C++ variables in the C style; this will help + disambiguate what's part of the Wirish API and what's not. + +- Classes: Pascal case. So ``ThisIsAClassName``, but ``thisIsNot``, + ``this_is_not``, and ``Dont_You_DareTryANYTHING_STUPID``. + +- Functions: C functions are all lowercase, and words are separated by + underscores. C++ method names are camel cased. + +- Structs: Usually like variables (``adc_dev``, ``adc_reg_map``, + etc.), but it's not crucial. Don't feel obliged to put ``_t`` at + the end of the type name; we don't. + +- Macros and constants: all caps, separated by underscores. C++ + variables with the ``const`` qualifier generally aren't considered + "constants" for the purposes of this rule; i.e., they are cased + according to the rules for variables. We make an exception for + ``PIN_MAP``, because it's the central Wirish data structure. + +- foo.h gets ``#ifdef``\ 'ed to ``_FOO_H_``. + +- Acronyms: The case of letters in an acronym is determined by the + case of the first letter in the acronym, which is determined by + following the above rules. Examples:: + + // Good: + void usb_func() { ... } + void frob_usb_disc() { ... } + class SomethingUSB { + void usbInit(); + void initUSB(); + }; + + // BAD: + class BadUsb { ... }; // say "GoodUSB" instead + void swizzle_USB_disc() { ... } // say "swizzle_usb_disc" instead + +Documentation +------------- + +- Doxygen comments on every user-facing function and type. + Additionally, individually document the fields and enumerator values + of nontrivial user-facing structs and enums. See any register map + type's definition for an example. + +- For libmaple proper, you don't need comments for each register bit + definition, since that's just repeating information better obtained + by reading ST RM0008. + +- Doxygen comments generally only belong on types, functions, + etc. that are part of the public user-facing API. This generally + means that if there's ReST documentation for it under libmaple's + ``docs/source/``, it needs Doxygen comments, and that ReST should + use Breathe to pull that Doxygen comment out. (For more information + on this, see libmaple file ``docs/README``). + + There are some exceptions to this rule since Breathe isn't totally + mature yet and Sphinx's C++ domain is still in flux. In these + cases, document the code "manually" in ReST. + + This should be avoided if at all possible, since it creates a + maintenance burden of documenting things in two places at once, and + makes it easier for documentation to go stale. + + If you do have to document something manually, put a comment in the + source file informing future maintainers about it, so they'll pay + extra attention when making changes. + +- When adding peripheral support, it would be nice if you put + longer-form comments into the libmaple ``notes/`` directory, with a + comment in the corresponding .h file referring to it. See the + :ref:`dac.h <libmaple-dac>` source for an example. + + This lets us keep the source files relatively free of "introductory" + material, while allowing new readers a convenient starting point. + These longer-form notes also have a habit of turning into official, + user-facing documentation. + +- **For libmaple proper**, the convention is to document any + user-facing function at the point where it is defined. In + particular, this means you should document an externally-linked + function defined in a .c file in that .c file, not in the header + file where it is declared to the user. + + **For Wirish**, the convention is to put the documentation in the + header file where the function is declared. + +General Formatting +------------------ + +.. highlight:: scheme + +- Keep it 80-column clean. + + Emacs users: this means that the largest column number is 79. You + should turn on column number mode to help you out:: + + (column-number-mode 1) + + You can get more help from `lineker-mode + <http://www.helsinki.fi/~sjpaavol/programs/lineker.el>`_. Just put + lineker.el somewhere in your load-path, and:: + + (require 'lineker) + (dolist (hook '(c-mode-hook c++-mode-hook)) + (add-hook hook (lambda () (lineker-mode 1)))) + +.. highlight:: cpp + +Language Features +----------------- + +In libmaple proper, aim for C99 compatibility. Some GCC extensions +are OK, but `don't get crazy <http://www.youtube.com/watch?v=jZkdcYlOn5M>`_. + +Explicitly approved GCC extensions: + + * `asm volatile <http://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html>`_ + + * `Nested functions <http://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html>`_ + +In Wirish, generally be very conservative when using C++ features that +aren't part of C. We are forced to use C++ for Arduino compatibility +(and the general Arduino style of conflating objects and libraries), +but it's an angry beast, and we don't want to provoke it. **The +mantra is "C with classes"**. + +Explicitly approved C++ features: + + * Initializers that aren't constant; e.g. the ``gpio_dev*`` values + in a ``PIN_MAP``. + + * Default arguments: e.g., the timeout argument in + :ref:`lang-waitforbuttonpress`. + +Explicitly forbidden C++ features: + + * Templates + +Conditionally allowed C++ features: + + * Operator overloading: Never allowed when it's just for style. + Probably fine when you're implementing a class that models a + mathematical structure, and you'd like to implement + e.g. ``operator+()``. + diff --git a/source/libmaple/contributing.rst b/source/libmaple/contributing.rst new file mode 100644 index 0000000..724605b --- /dev/null +++ b/source/libmaple/contributing.rst @@ -0,0 +1,113 @@ +.. _libmaple-contributing: + +Contributing to libmaple +======================== + +First of all, thanks! Community contributions are what makes open +source great. + +If your patch is minor (you've found a typo, you've added a new +function, etc.), feel free to just make a `forum post +<http://forums.leaflabs.com>`_ describing your changes. + +If your changes are larger (you wrote a new library, you added support +for a new peripheral, etc.), we'd prefer you submit a pull request on +Github or send us a nicely-formatted patch via email. + +.. contents:: Contents + :local: + +.. _libmaple-faq-patches-preparing: + +Preparing Your Patch +-------------------- + +Before submitting a patch, please make sure it complies with the +:ref:`coding standard <libmaple-coding-standard>`. Consistent style throughout +the source tree is an important implementation objective for us, and a +patch that doesn't comply with the coding standard we've set forth is +likely to be sent back until it follows the standard. + +We would prefer if you release each new file you submit under the `MIT +license <http://www.opensource.org/licenses/mit-license.php>`_. See +e.g. `bkp.h +<https://github.com/leaflabs/libmaple/blob/master/libmaple/bkp.h#L1>`_ +for an example, and the coding standard for more details. Code +released under the `Lesser GPL +<http://www.gnu.org/copyleft/lesser.html>`_ may be accepted for +Wirish, but will almost certainly be rejected for libmaple proper. We +will not accept patches released under the `GPL +<http://www.gnu.org/licenses/gpl.html>`_. + +**We're not against the GPL**! It just doesn't suit our purposes for +libmaple. If you're interested in a GPLed library for ST +microcontrollers, check out `libopenstm32 +<http://www.hermann-uwe.de/blog/libopenstm32-a-free-software-firmware-library-for-stm32-arm-cortex-m3-microcontrollers>`_. +Also note that :ref:`libraries <libraries>` released under the GPL are +fine, we just don't want any core libmaple or Wirish code to be GPLed. + +.. _libmaple-faq-patches-github: + +Submitting Via Github Pull Request (Preferred) +---------------------------------------------- + +The most convenient way for you to contribute patches is to submit a +pull request on `Github <https://github.com>`_. Github provides +excellent code review interfaces, which will make it easy for us at +LeafLabs to communicate with you (and each other) about your patch. +It also makes it easy for us to merge your patch into the libmaple +source tree when the time comes. + +The steps to submit a pull request are as follows: + +1. If you don't already have one, get a `Github account + <https://github.com/plans>`_ (free). + +2. Fork libmaple, then clone your fork to the computer you code on. + Github provides detailed instructions on `forking and cloning a + repository <http://help.github.com/fork-a-repo/>`_. + +3. Push your commits to your Github libmaple fork (see instructions + linked in Step 2 for a step-by-step walkthrough on how to do this). + +4. `Submit a pull request <http://help.github.com/pull-requests/>`_ to + the LeafLabs version of libmaple. + +.. _libmaple-faq-patches-email: + +Submitting Via Email +-------------------- + +If you're unfamiliar with Git or would prefer not to use Github, you +can always send us a patch via email at info@leaflabs.com. We'd love +it if you used the `Linux kernel patch format +<http://linux.yyz.us/patch-format.html>`_, but please at least include +the following information in your email: + +1. How you generated your patch (arguments to ``diff``, etc.) + +2. What git branch/commit or libmaple version your patch applies to + +3. A one-line summary of your changes, along with any other details + you think we should know. + +4. A sign-off line certifying your `developer certificate of origin + <http://elinux.org/Developer_Certificate_Of_Origin>`_. + +That said, we'd really prefer a pull request. If you'd like to learn +more about Git, we recommend the following resources: + +* `The Git Community Book <http://book.git-scm.com/index.html>`_: A + collaboratively edited book on Git. + +* `Pro Git <http://progit.org/book/>`_: despite its title, this is a + fairly beginner-friendly source of information. + +* `Understanding Git Conceptually + <http://www.eecs.harvard.edu/~cduan/technical/git/>`_: a good, + introductory tutorial on Git's fundamental concepts. + +* `Git for Computer Scientists + <http://eagain.net/articles/git-for-computer-scientists/>`_: if + you're comfortable with directed acyclic graphs, this resource + explains Git's functionality in graph-theoretic terms. diff --git a/source/libmaple/overview.rst b/source/libmaple/overview.rst new file mode 100644 index 0000000..9bce564 --- /dev/null +++ b/source/libmaple/overview.rst @@ -0,0 +1,342 @@ +.. highlight:: c + +.. _libmaple-overview: + +Overview +======== + +This page is a general overview of the low-level aspects of libmaple +proper. It provides a general perspective of the library's goals and +design. Examples are given from the libmaple sources. + +.. contents:: Contents + :local: + +Design Goals +------------ + +The central goal of the libmaple project is to provide a pleasant, +consistent set of interfaces for dealing with the various peripherals +on the STM32 line. + +Let's start with the basics. If you're interested in low-level details +on the STM32, then you're going to spend a lot of quality time wading +through `ST RM0008 +<http://www.st.com/stonline/products/literature/rm/13902.pdf>`_. +RM0008 is the single most important tool in your toolbox. It is the +authoritative documentation for the capabilities and low-level +programming interfaces of ST's line of ARM Cortex M3 microcontrollers. + +Perhaps you haven't read it in detail, but maybe you've at least +thumbed through a few of the sections, trying to gain some +understanding of what's going on. If you've done that (and if you +haven't, just take our word for it), then you know that underneath the +covers, *everything* is controlled by messing with bits in the +seemingly endless collections of registers specific to every +peripheral. The `USARTs <http://leaflabs.com/docs/usart.html>`_ have +data registers; (some of the) the `timers +<http://leaflabs.com/docs/timers.html>`_ have capture/compare +registers, the `GPIOs <http://leaflabs.com/docs/gpio.html>`_ have +output data registers, etc. + +For the most part, Wirish does everything it can to hide this truth +from you. That's because when you really just want to get your robot +to fly, your LEDs to blink, or your `FM synthesizer +<https://github.com/Ixox/preen>`_ to, well, `synthesize +<http://xhosxe.free.fr/IxoxFMSynth.mp3>`_, you probably couldn't care +less about messing with registers. + +That's fine! In fact, it's our explicit goal for Wirish to be good +enough that most people never need to know libmaple proper even +exists. We want to make programming our boards as easy as possible, +after all. But the day may come when you want to add a library for an +as-yet unsupported peripheral, or you want to do something we didn't +anticipate, or you'd like to squeeze a little more speed out of a +critical section in your program. Or maybe you're just curious! + +If anything in the above paragraph describes you, then you'll find +that you need a way to translate your knowledge of RM0008 into +software. We imagine (if you're anything like us) you want to spend +the least amount of time you possibly can doing that +translation. Ideally, once you've finished your design, you want some +way to start reading and writing code right away, without having to +bushwhack your way through a thicket of clunky APIs. + +The central abstractions we've chosen to accomplish the above goals +are *register maps* and *devices*. Register maps are just structs +which encapsulate the layout of the IO-mapped memory regions +corresponding to a peripheral's registers. Devices encapsulate a +peripheral's register map as well as any other necessary information +needed to operate on it. Peripheral support routines generally +operate on devices rather than register maps. + +Devices +------- + +At the highest level, you'll be dealing with *devices*, where a +"device" is a general term for any particular piece of hardware you +might encounter. So, for example, an analog to digital converter is a +device. So is a USART. So is a GPIO port. In this section, we'll +consider some hypothetical "xxx" device. + +The first thing you need to know is that the header file for dealing +with xxx devices is, naturally enough, called ``xxx.h``. So if you +want to interface with the :ref:`ADCs <adc>`, just ``#include +"adc.h"``. + +Inside of ``xxx.h``, there will be a declaration for a ``struct +xxx_dev`` type. This type encapsulates all of the information we keep +track of for that xxx. So, for example, in ``adc.h``, there's a +``struct adc_dev``:: + + /** ADC device type. */ + typedef struct adc_dev { + adc_reg_map *regs; /**< Register map */ + rcc_clk_id clk_id; /**< RCC clock information */ + } adc_dev; + +The ADCs aren't particularly complicated. All we keep track of for an +ADC device is a pointer to its register map (which keeps track of all +of its registers' bits; see :ref:`below <libmaple-overview-regmaps>` +for more details), and an identifying piece of information which tells +the RCC (reset and clock control) interface how to turn the ADC on and +reset its registers to their default values. + +The timers on the STM32 line are more involved than the ADCs, so a +``timer_dev`` has to keep track of a bit more information:: + + /** Timer device type */ + typedef struct timer_dev { + timer_reg_map_union regs; + rcc_clk_id clk_id; + timer_type type; + voidFuncPtr handlers[]; + } timer_dev; + +However, as you can see, both ADC and timer devices are named +according to a single scheme, and store similar information. + +``xxx.h`` will also declare pointers to the actual devices you need to +deal with, called ``XXX1``, ``XXX2``, etc. (or just ``XXX``, if +there's only one) [#fgpio]_. For instance, on the Maple's +microcontroller (the STM32F103RBT6), there are two ADCs. +Consequently, in ``adc.h``, there are declarations for dealing with +ADC devices one and two:: + + extern const adc_dev *ADC1; + extern const adc_dev *ADC2; + +In general, each device needs to be initialized before it can be used. +libmaple provides this initialization routine for each peripheral +``xxx``; its name is ``xxx_init()``. These initialization routines +turn on the clock to a device, and restore its register values to +their default settings. Here are a few examples:: + + /* From dma.h */ + void dma_init(dma_dev *dev); + + /* From gpio.h */ + void gpio_init(gpio_dev *dev); + void gpio_init_all(void); + +Note that, sometimes, there will be an additional initialization +routine for all available peripherals of a certain kind. + +Many peripherals also need additional configuration before they can be +used. These functions are usually called something along the lines of +``xxx_enable()``, and often take additional arguments which specify a +particular configuration for the peripheral. Some examples:: + + /* From usart.h */ + void usart_enable(usart_dev *dev); + + /* From i2c.h */ + void i2c_master_enable(i2c_dev *dev, uint32 flags); + +After you've initialized, and potentially enabled, your peripheral, it +is now time to begin using it. The file ``xxx.h`` contains other +convenience functions for dealing with xxx devices. For instance, +here are a few from ``adc.h``:: + + void adc_set_sample_rate(const adc_dev *dev, adc_smp_rate smp_rate); + uint32 adc_read(const adc_dev *dev, uint8 channel); + +We aim to enable libmaple's users to interact with peripherals through +devices as much as possible, rather than having to break the +abstraction and consider individual registers. However, there will +always be a need for low-level access. To allow for that, libmaple +provides *register maps* as a consistent set of names and abstractions +for dealing with registers and their bits. + +.. _libmaple-overview-regmaps: + +Register Maps +------------- + +A *register map* is just a C struct which names and provides access to +a peripheral's registers. These registers are usually mapped to +contiguous regions of memory (though at times unusable or reserved +regions exist between a peripheral's registers). Here's an example +register map, from ``dac.h`` (``__io`` is just libmaple's way of +saying ``volatile`` when referring to register values):: + + /** DAC register map. */ + typedef struct dac_reg_map { + __io uint32 CR; /**< Control register */ + __io uint32 SWTRIGR; /**< Software trigger register */ + __io uint32 DHR12R1; /**< Channel 1 12-bit right-aligned data + holding register */ + __io uint32 DHR12L1; /**< Channel 1 12-bit left-aligned data + holding register */ + __io uint32 DHR8R1; /**< Channel 1 8-bit left-aligned data + holding register */ + __io uint32 DHR12R2; /**< Channel 2 12-bit right-aligned data + holding register */ + __io uint32 DHR12L2; /**< Channel 2 12-bit left-aligned data + holding register */ + __io uint32 DHR8R2; /**< Channel 2 8-bit left-aligned data + holding register */ + __io uint32 DHR12RD; /**< Dual DAC 12-bit right-aligned data + holding register */ + __io uint32 DHR12LD; /**< Dual DAC 12-bit left-aligned data + holding register */ + __io uint32 DHR8RD; /**< Dual DAC 8-bit left-aligned data holding + register */ + __io uint32 DOR1; /**< Channel 1 data output register */ + __io uint32 DOR2; /**< Channel 2 data output register */ + } dac_reg_map; + + +There are two things to notice here. First, if RM0008 names a +register ``DAC_FOO``, then ``dac_reg_map`` has a field named ``FOO``. +So, the Channel 1 12-bit right-aligned data register (RM0008: +DAC_DHR12R1) is the ``DHR12R1`` field in a ``dac_reg_map``. Second, +if RM0008 describes a register as "Foo bar register", the +documentation for the corresponding field has the same description. +This consistency makes it easy to search for a particular register, +and, if you see one used in a source file, to feel sure about what's +going on just based on its name. + +So let's say you've included ``xxx.h``, and you want to mess with some +particular register. What's the name of the ``xxx_reg_map`` variable +you want? That depends on if there's more than one xxx or not. If +there's only one xxx, then libmaple guarantees there will be a +``#define`` that looks like like this:: + + #define XXX_BASE ((xxx_reg_map*)0xDEADBEEF) + +That is, you're guaranteed there will be a pointer to the (only) +``xxx_reg_map`` you want, and it will be called +``XXX_BASE``. (``0xDEADBEEF`` is the register map's *base address*, or +the fixed location in memory where the register map begins). Here's a +concrete example from ``dac.h``:: + + #define DAC_BASE ((dac_reg_map*)0x40007400) + +How can you use these? This is perhaps best explained by example. + +* In order to write 2048 to the channel 1 12-bit left-aligned data + holding register (RM0008: DAC_DHR12L1), you could write:: + + DAC_BASE->DHR12L1 = 2048; + +* In order to read the DAC control register, you could write:: + + uint32 cr = DAC_BASE->CR; + +The microcontroller takes care of converting reads and writes from a +register's IO-mapped memory regions into reads and writes to the +corresponding hardware registers. + +That covers the case where there's a single xxx peripheral. If +there's more than one (say, if there are *n*), then ``xxx.h`` provides +the following:: + + #define XXX1_BASE ((xxx_reg_map*)0xDEADBEEF) + #define XXX2_BASE ((xxx_reg_map*)0xF00DF00D) + ... + #define XXXn_BASE ((xxx_reg_map*)0x13AF1AB5) + +Here's a concrete example from ``adc.h``:: + + /** ADC1 register map base pointer. */ + #define ADC1_BASE ((adc_reg_map*)0x40012400) + /** ADC2 register map base pointer. */ + #define ADC2_BASE ((adc_reg_map*)0x40012800) + /** ADC3 register map base pointer. */ + #define ADC3_BASE ((adc_reg_map*)0x40013C00) + +In order to read from the ADC1's regular data register (where the +results of ADC conversion are stored), you might write:: + + uint32 converted_result = ADC1->DR; + +Register Bit Definitions +------------------------ + +In ``xxx.h``, there will also be a variety of #defines for dealing +with interesting bits in the xxx registers, called *register bit +definitions*. These are named according to the scheme +``XXX_REG_FIELD``, where "``REG``" refers to the register, and +"``FIELD``" refers to the bit or bits in ``REG`` that are special. + +.. TODO image of the bit layout of a DMA_CCR register + +Again, this is probably best explained by example. Each Direct Memory +Access (DMA) controller's register map has a certain number of channel +configuration registers (RM0008: DMA_CCRx). In each of these channel +configuration registers, bit 14 is called the ``MEM2MEM`` bit, and +bits 13 and 12 are the priority level (``PL``) bits. Here are the +register bit definitions for those fields:: + + /* From dma.h */ + + #define DMA_CCR_MEM2MEM_BIT 14 + #define DMA_CCR_MEM2MEM BIT(DMA_CCR_MEM2MEM_BIT) + #define DMA_CCR_PL (0x3 << 12) + #define DMA_CCR_PL_LOW (0x0 << 12) + #define DMA_CCR_PL_MEDIUM (0x1 << 12) + #define DMA_CCR_PL_HIGH (0x2 << 12) + #define DMA_CCR_PL_VERY_HIGH (0x3 << 12) + +Thus, to check if the ``MEM2MEM`` bit is set in DMA controller 1's +channel configuration register 2 (RM0008: DMA_CCR2), you can write:: + + if (DMA1_BASE->CCR2 & DMA_CCR_MEM2MEM) { + /* MEM2MEM is set */ + } + +Certain register values occupy multiple bits. For example, the +priority level (PL) of a DMA channel is determined by bits 13 and 12 +of the corresponding channel configuration register. As shown above, +libmaple provides several register bit definitions for masking out the +individual PL bits and determining their meaning. For example, to +check the priority level of a DMA transfer, you can write:: + + switch (DMA1_BASE->CCR2 & DMA_CCR_PL) { + case DMA_CCR_PL_LOW: + /* handle low priority case */ + case DMA_CCR_PL_MEDIUM: + /* handle medium priority case */ + case DMA_CCR_PL_HIGH: + /* handle high priority case */ + case DMA_CCR_PL_VERY_HIGH: + /* handle very high priority case */ + } + +Of course, before doing that, you should check to make sure there's +not already a device-level function for performing the same task! + +What Next? +---------- + +After you've read this page, you can proceed to the :ref:`libmaple API +listing <libmaple-apis>`. From there, you can read documentation and +follow links to the current source code for those files on `libmaple's +Github page <https://github.com/leaflabs/libmaple>`_. + +.. rubric:: Footnotes + +.. [#fgpio] For consistency with RM0008, GPIO ports are given letters + instead of numbers (``GPIOA`` and ``GPIOB`` instead of + ``GPIO1`` and ``GPIO2``, etc.). |