diff options
Diffstat (limited to 'notes')
| -rw-r--r-- | notes/coding_standard.rst | 427 | ||||
| -rw-r--r-- | notes/coding_standard.txt | 223 | ||||
| -rw-r--r-- | notes/dma.txt | 99 | ||||
| -rw-r--r-- | notes/exti.txt | 67 | ||||
| -rw-r--r-- | notes/pin-definitions.txt (renamed from notes/native-pin-definitions.txt) | 27 | ||||
| -rw-r--r-- | notes/portable.txt | 94 | ||||
| -rw-r--r-- | notes/timers.txt | 152 | ||||
| -rw-r--r-- | notes/usb.txt | 4 | ||||
| -rw-r--r-- | notes/vga.txt | 9 | 
9 files changed, 700 insertions, 402 deletions
| diff --git a/notes/coding_standard.rst b/notes/coding_standard.rst new file mode 100644 index 0000000..f761db7 --- /dev/null +++ b/notes/coding_standard.rst @@ -0,0 +1,427 @@ +libmaple Coding Standards +========================= + +Author: Marti Bolivar (mbolivar@leaflabs.com) + +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, do it like this unless there's a really good reason why +not.  You being lazy 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. + +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 (hint, hint)! + +.. 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/Indentation +---------------------- + +- 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 this: + +      http://github.com/mbolivar/code-fascism + +  I hear tell you can get something similar in Vim; ask around, I +  guess. + +- 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.  This doesn't apply to the +  . and -> operators.  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 + +.. highlight:: scheme + +  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 on the same line are ``//`` in C++. (That's OK +  in C as well). + +- Single-line comments on their own source line should be ``/* */`` in +  C, but can also be ``//`` in C++.  (This isn't of great importance). +  In Emacs, you can use M-; (comment-dwim), and it'll Do What You +  Mean. + +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 +------------------ + +There's always a fight about upper and lower case vs. underscores. +We'll handle this 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 like I said, +  ``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 +------------- + +- You **must** document your code.  At a bare minimum, this means +  Doxygen comments on every user-facing function and type. +  Additionally, you need to individually document the fields and +  enumerator values of ``struct``\ s and ``enum``\ s.  See any +  register map type's definition for an example. + +- For libmaple proper, you don't need comments for each register bit +  definition (for now). + +- Doxygen comments generally just 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 docs/source/, +  it needs Doxygen comments, and that ReST should use Breathe to pull +  that Doxygen comment out. (For more info on this, see 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 /notes/ directory, with a comment in +  the corresponding .h file referring to it.  See /libmaple/dac.h 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 +  user-facing documentation. + +- For libmaple proper (the pure C library under libmaple/); 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. + +General Formatting +------------------ + +.. highlight:: scheme + +- Keep it 80-column clean.  That means Emacs says the largest column +  number=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 and Compiler Extensions +----------------------------------------- + +- In libmaple proper, aim for C99 compatibility.  Some GCC extensions +  are OK, but let's not go crazy.   + +- If you'd like to get code into libmaple which uses a GCC extension +  not already in use elsewhere, ask a LeafLabs developer (or another +  one, if you are one) what they think about it first. + +- 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 pretending that an +  object is a library), 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 defaulting to 0 +    (meaning to wait forever) in ``waitForButtonPress()``. + +- Explicitly forbidden C++ features: + +  * Templates + +- C++ features that are conditionally allowed, but require explicit +  approval from at least two libmaple developers (one of which may be +  yourself): + +  * Operator overloading: Never allowed when it's just for style. +    Potentially allowed when you're implementing a class that models a +    mathematical structure, and you'd like to implement +    e.g. ``operator+()``. diff --git a/notes/coding_standard.txt b/notes/coding_standard.txt deleted file mode 100644 index 5cb96c3..0000000 --- a/notes/coding_standard.txt +++ /dev/null @@ -1,223 +0,0 @@ -libmaple Coding Standards -========================= - -Author: Marti Bolivar (mbolivar@leaflabs.com) - -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, do it like this unless there's a really good reason why -not.  You being lazy 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. - -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 (hint, hint)! - -License -------- - -- Put an MIT license at the beginning of the file (look at any of our -  source files for an example).  Copyright should go to either you or -  LeafLabs LLC. - -  Emacs: if you don't like seeing the license, you should use -  elide-head (which will hide it for you).  Here is some elisp you can -  modify to make this pleasant: - -    (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 mbolivar-programming-mode-hooks) -      (add-hook hook (lambda () (elide-head)))) - -Whitespace/Indentation ----------------------- - -- 4 space indents.  [Set in .dir-locals.el] - -- Unix newlines. - -- 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 this: - -    http://github.com/mbolivar/code-fascism - -  I hear tell you can get something similar in vim; ask around, I -  guess. - -- 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. - -- Don't indent C code within a conditionally-compiled extern "C" -  block.  Emacs does this by default, which can be very annoying; you -  can turn this behavior 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 --------- - -- Multi-line comments look like this: - -    /* text starts here -     * continued lines have a '*' before them -     * the comment can end after the last line -     */ - -  or this: - -    /* comment starts here -     * the comment can end on the same line */ - -- Doxygen comments are newline comments that begin with /** instead. -  It is not required that the "/**" appear on a line by itself. - -- Single-line comments on the same line are // in c or c++. - -- Single-line comments on their own source line are /* */ in c, but -  can also be // in c++.  If you think that typing out /* */ is too -  slow in emacs, use M-; (comment-dwim) when you're on an empty line, -  and it'll ... well... - -      You should be using the (super awesome) comment-dwim; it pretty -      much does exactly what you want to the comment on the current -      line, including "create one and put it in the right place". - -Braces ------- - -- 1TBS.  Nothing more need be said. - -      http://en.wikipedia.org/wiki/Indent_style#Variant:_1TBS - -Naming conventions ------------------- - -- There's always a fight about upper and lower case vs. underscores. -  We'll handle this as follows. - -  First, Dammit_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; - -  It is strongly advised to do it this way in C++ too, but it's not -  [yet] mandatory. - -- Classes: Pascal case.  So ThisIsAClassName, but thisIsNot, -  this_is_not, and like I said, Dont_You_DareTryANYTHING_STUPID. - -- Functions: C functions are all lowercase, and words are separated by -  underscores.  C++ method names are camel cased (thisIsAnExample). - -- Structs: pick a style from "Variables" or "Classes" depending on how -  you mean it (since it might be either a simple record type, in which -  case do like c variables, or you might be faking an object in c, in -  which case do like classes).  If it's in a typedef, don't feel -  obliged to put "_t" at the end of the name; we don't. - -- Macros and constants: all caps, separated by underscores.  Variables -  with the "const" qualifier aren't considered "constants" for the -  purposes of this rule; i.e., case them according to the rules for -  variables. - -- 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: - -      void usb_func() { ... } - -      class SomethingUSB { -          void usbInit(); -          void initUSB(); -      }; - -  Never do this: - -      class BadUsb { ... }; // say "GoodUSB" instead - -Documentation -------------- - -- Document your code.  This should go without saying. - -- For complicated peripherals, it would be nice if you put longer-form -  comments into this directory (notes/), with a comment in the -  corresponding .h file referring to it.  See libmaple/dac.h for an -  example.  That lets us keep the source files relatively clean while -  still allowing new readers to have a starting point. - -- At least put a doxygen comment with a nonempty @brief for every .h -  file you add.  See the existing ones for examples.  For now, it'd be -  better if you didn't put a @brief into any .c[pp] files, since it -  (currently) interferes with our documentation generator in a way -  that I won't explain here (though you can look into the LeafLabs or -  michaeljones breathe repos on github and potentially figure out -  why). - -- Doxygen comments generally just 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 docs/source/, -  it needs Doxygen comments, and that ReST should use Breathe to pull -  that Doxygen comment out. (For more info on this, see 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 -  provides an opportunity for bad documentation to slip in, when the -  code comments fall out of sync with the ReST docs. - -General Formatting ------------------- - -- Keep it 80-column clean.  That means Emacs says the largest column -  number=79.  If you haven't already, you should turn on column -  numbers to help you out: - -    (column-number-mode 1) - -  You can get more help from lineker-mode.  Download it here: - -    http://www.helsinki.fi/~sjpaavol/programs/lineker.el - -  Then put the file somewhere in your load-path, and: - -    (require 'lineker) -    (dolist (hook '(c-mode-hook c++-mode-hook)) -      (add-hook hook (lambda () (lineker-mode 1)))) - -  There are only a few exceptional situations.  The most important one -  is when specifying a lookup table like PIN_MAP where it'd be ugly to -  split each entry over multiple lines. diff --git a/notes/dma.txt b/notes/dma.txt new file mode 100644 index 0000000..97b23a0 --- /dev/null +++ b/notes/dma.txt @@ -0,0 +1,99 @@ +DMA Notes +========= + +Medium-density devices have one DMA controller, DMA1.  High-density +devices and up also have DMA2.  DMA1 has 7 channels; DMA2 has 5.  Each +channel multiplexes DMA requests from various peripherals, like so: + +Channel Capabilities +-------------------- + +DMA1: + +    * Channel 1: ADC1, TIM2_CH3, TIM4_CH1 +    * Channel 2: USART3_TX, TIM1_CH1, TIM2_UP,  TIM3_CH3, SPI1_RX +    * Channel 3: USART3_RX, TIM1_CH2, TIM3_CH4, TIM3_UP,  SPI1_TX +    * Channel 4: USART1_TX, TIM1_CH4, TIM1_TRIG, TIM1_COM, TIM4_CH2, +                 SPI2/I2S2_RX, I2C2_TX +    * Channel 5: USART1_RX, TIM1_UP, TIM2_CH1, TIM4_CH3, +                 SPI2/I2S2_TX, I2C2_RX +    * Channel 6: USART2_RX, TIM1_CH3, TIM3_CH1, TIM3_TRIG, I2C1_TX +    * Channel 7: USART2_TX, TIM2_CH2, TIM2_CH4, TIM4_UP, I2C1_RX + +DMA2: + +    * Channel 1: TIM5_CH4, TIM5_TRIG, TIM8_CH3, TIM8_UP, SPI/I2S3_RX +    * Channel 2: TIM8_CH4, TIM8_TRIG, TIM8_COM, TIM5_CH3, TIM5_UP, SPI/I2S3_TX +    * Channel 3: TIM8_CH1, UART4_RX, TIM6_UP/DAC_CH1 +    * Channel 4: TIM5_CH2, SDIO, TIM7_UP/DAC_CH2 +    * Channel 5: ADC3, TIM8_CH2, TIM5_CH1, UART4_TX + +An example usage: via DMA1, channel 1, you can have ADC1 periodically +dump converted data into an array in memory.  The DMA controller can +then interrupt you when the array is half-full and full, and if any +error occurred. + +Since channels are multiplexed in hardware, you can't simultaneously +use the same DMA channel to serve requests from two of its peripherals +at the same time.  For example, if you are using DMA 1 channel 1 to +serve DMA requests from ADC1, you can't also serve requests from Timer +2 channel 3. + +Channel Priority +---------------- + +An arbiter prioritizes simultaneous channel DMA requests.  Channel +priority levels are configurable (4 levels of priority).  Ties within +a DMA controller are broken by choosing the lower channel number; +between the controllers, DMA1 has higher priority than DMA2. + +Interrupts +---------- + +You can cause an interrupt to fire once half the transfers are +complete, when all the transfers are complete, if an error occurs +during transfer, or any combination of the three. + +If an error occurs, the transfer is automatically disabled. + +Configuration +------------- + +In order to configure a DMA transfer for DMA controller n, channel x, +ST RM0008 says you should do the following: + +    A. Set the peripheral register address in DMAn_BASE->CPARx. +    B. Set the memory address in DMAn_BASE->CMARx. +    C. Set the number of data to be transferred in DMAn_BASE->CNDTRx. +    D. Set the channel priority via the PL bits in DMAn_BASE->CCRx. +    E. Configure various other things (e.g. data transfer sizes, what +       events cause channel interrupts) in DMAn_BASE->CCRx as desired. +    F. Activate the channel by setting ENABLE bit in DMAn_BASE->CCRx. + +The channel will start serving DMA requests as soon as it's activated. + +The DMA library lets you accomplish these tasks as follows: + +    **Setup transfer** + +    Do (A), (B), and (E) using dma_setup_transfer(). + +    This also does (D), but chooses the lowest priority by default. + +    **Perform any other desired configuration** + +    You can do (C) using dma_set_num_transfers(). + +    You can do (D) using dma_set_priority(). + +    You can attach interrupt handlers with dma_attach_interrupt(). + +    **Activate the channel** + +    Do (F) with dma_enable(). + +Once you're all done, you can dma_disable() the channel.  If you +dma_detach_interrupt() an interrupt handler, the channel interrupts +will stop firing, but the transfer itself won't stop until it's done +(which never happens if you set the DMA_CIRC_MODE flag when you called +dma_setup_transfer()). diff --git a/notes/exti.txt b/notes/exti.txt new file mode 100644 index 0000000..1ad49ee --- /dev/null +++ b/notes/exti.txt @@ -0,0 +1,67 @@ +External interrupt notes. + +To generate the interrupt, the interrupt line should be configured +and enabled. This is done by programming the two trigger registers +with the desired edge detection and by enabling the interrupt +request by writing a '1' to the corresponding bit in the interrupt +mask register.  When the selected edge occurs on the external +interrupt line, an interrupt request is generated. The pending bit +corresponding to the interrupt line is also set.  This request is +reset by writing a '1' in the pending register. + +Hardware interrupt selection: + +To configure the 20 lines as interrupt sources, use the following +procedure: + +1) Configure AFIO_EXTICR[y] to select the source input for EXTIx +   external interrupt +2) Configure the mask bits of the 20 interrupt lines (EXTI_IMR) +3) Configure the trigger selection bits of the interrupt lines +   (EXTI_RTSR and EXTI_FTSR) +4) Configure the enable and mask bits that control the NVIC_IRQ +   channel mapped to the External Interrupt Controller (EXTI) so +   that an inerrupt coming from one of the 20 lines can be +   correctly acknowledged. + +AFIO clock must be on. + +RM0008, page 107: "PD0, PD1 cannot be used for external +interrupt/event generation on 36, 48, 64-bin packages." + +---------------------------------------------------------------------------- +Pin to EXTI Line Mappings: +EXTI0          EXTI1          EXTI2           EXTI3           EXTI4 +-------------------------------------------------------------------------- +D2/PA0         D3/PA1         D1/PA2          D0/A6/PA3       D10/A10/PA4 +D26/EXT7/PB0   D27/EXT8/PB1   D16/A2/PC2      D17/A3/PC3      D18/A4/PC4 +D14/A0/PC0     D15/PC1        D25/EXT5/PD2 + +EXTI5          EXTI6          EXTI7           EXTI8           EXTI9 +---------------------------------------------------------------------------- +D13/A13/PA5    D12/A12/PA6    D11/A11/PA7     D6/PA8          D7/PA9 +D4/PB5         D5/PB6         D9/PB7          D38/PB8         D23/EXT4/PB9 +D19/A5/PC5     D34/EXTI15/PC6 D35/EXT16/PC7   D36/PC8         D37/EXT18/PC9 + +EXTI10         EXTI11         EXTI12          EXTI13          EXTI14 +---------------------------------------------------------------------------- +D8/PA10        D29/EXT10/PB11 D30/EXTI1/PB12  D31/EXTI12/PB13 D32/EXT13/PB14 +D28/PB10                                      D20/EXTI1/PC13  D21/EXT2/PC14 +D25/PC10 + +EXTI15 +---------------------------------------------------------------------------- +D33/EXTI14/PB15 +D22/EXT3/PC15 + + +The 16 EXTI interrupts are mapped to 7 interrupt handlers. + +EXTI Lines to Interrupt Mapping: +EXTI0 -> EXTI0 +EXTI1 -> EXTI1 +EXTI2 -> EXTI2 +EXTI3 -> EXTI3 +EXTI4 -> EXTI4 +EXTI[5-9] -> EXT9_5 +EXTI[10-15] -> EXT15_10 diff --git a/notes/native-pin-definitions.txt b/notes/pin-definitions.txt index b871f89..30f5056 100644 --- a/notes/native-pin-definitions.txt +++ b/notes/pin-definitions.txt @@ -1,21 +1,18 @@ -Maple Native (STM32F103ZE) pin definitions, by GPIO bank. +Pin definitions by GPIO bank.  Source: ST DOC ID 14611, Datasheet for STM32F103xC, STM32F103xD,  STM32F103xE, Table 5, pp. 30--35. -Some peripherals and extra functionality with less/no libmaple -relevance (at time of writing) are given in "Other" following each -bank's main table.  Non-default alternate functions are not listed. If -wirish will/does remap the pin's main function after reset, the main -function is listed under "Other". +Some additional peripheral GPIO information is given in the "Other" +section following each bank's main table. -This document was prepared carefully and is believed to be complete -and correct, but the final arbiter of truth is the ST datasheet. +This document was prepared carefully and is believed to be correct, +but the final arbiter of truth is the ST datasheet.  *** NB: UART 4 and 5 are NOT USART (columns are labeled appropriately).  --------------------------------------------------------------------------- -STM32   ADC     Timer   FSMC    I2S     I2C     USART   SPI     DAC     5v? +GPIO    ADC     Timer   FSMC    I2S     I2C     USART   SPI     DAC     5v?  ---------------------------------------------------------------------------  PA0     123in0  2ch1etr -       -       -       2cts    -       -       -                  5ch1 @@ -52,7 +49,7 @@ PA14: JTCK-SWCLK (default)  PA15: JTDI (default)  ------------------------------------------------------------------------------- -STM32   ADC     Timer   FSMC    I2S     I2C     USART   SPI     DAC    5v? SDIO +GPIO    ADC     Timer   FSMC    I2S     I2C     USART   SPI     DAC    5v? SDIO  -------------------------------------------------------------------------------  PB0     12in8   3ch3    -       -       -       -       -       -      -   -                  8ch2n @@ -80,7 +77,7 @@ PB3: JTDO (default)  PB4: NJTRST (default)  ------------------------------------------------------------------------------- -STM32   ADC     Timer   FSMC    I2S     I2C     UART    SPI     DAC    5v? SDIO +GPIO    ADC     Timer   FSMC    I2S     I2C     UART    SPI     DAC    5v? SDIO  -------------------------------------------------------------------------------  PC0     123in10 -       -       -       -       -       -       -      -   -  PC1     123in11 -       -       -       -       -       -       -      -   - @@ -106,7 +103,7 @@ PC14: OSC32_IN  PC15: OSC32_OUT  ------------------------------------------------------------------------------- -STM32   ADC     Timer   FSMC    I2S     I2C     UART    SPI     DAC    5v? SDIO +GPIO    ADC     Timer   FSMC    I2S     I2C     UART    SPI     DAC    5v? SDIO  -------------------------------------------------------------------------------  PD0     -       -       D2      -       -       -       -       -      Y   -  PD1     -       -       D3      -       -       -       -       -      Y   - @@ -132,7 +129,7 @@ PD0: OSC_IN (default)  PD1: OSC_OUT (default)  --------------------------------------------------------------------------- -STM32   ADC     Timer   FSMC    I2S     I2C     USART   SPI     DAC     5v? +GPIO    ADC     Timer   FSMC    I2S     I2C     USART   SPI     DAC     5v?  ---------------------------------------------------------------------------  PE0     -       4etr    NBL0    -       -       -       -       -       Y  PE1     -       -       NBL1    -       -       -       -       -       Y @@ -159,7 +156,7 @@ PE5: TRACED2  PE6: TRACED3  --------------------------------------------------------------------------- -STM32   ADC     Timer   FSMC    I2S     I2C     USART   SPI     DAC     5v? +GPIO    ADC     Timer   FSMC    I2S     I2C     USART   SPI     DAC     5v?  ---------------------------------------------------------------------------  PF0     -       -       A0      -       -       -       -       -       Y  PF1     -       -       A1      -       -       -       -       -       Y @@ -179,7 +176,7 @@ PF14    -       -       A8      -       -       -       -       -       Y  PF15    -       -       A9      -       -       -       -       -       Y  --------------------------------------------------------------------------- -STM32   ADC     Timer   FSMC    I2S     I2C     USART   SPI     DAC     5v? +GPIO    ADC     Timer   FSMC    I2S     I2C     USART   SPI     DAC     5v?  ---------------------------------------------------------------------------  PG0     -       -       A10     -       -       -       -       -       Y  PG1     -       -       A11     -       -       -       -       -       Y diff --git a/notes/portable.txt b/notes/portable.txt index 69952d7..cc1f2ac 100644 --- a/notes/portable.txt +++ b/notes/portable.txt @@ -1,98 +1,28 @@ +Board portability is implemented in boards.h, libmaple.h, and stm32.h. -Disclaimer text:  // High-density devices only (Maple Native) +At compile time, we currently expect one of STM32_MEDIUM_DENSITY or +STM32_HIGH_DENSITY to be defined.  There's no support for low-density +chips.  XL-density isn't in the near horizon; patches welcome.  You'll +also need to define some BOARD_foo if you expect to use Wirish; this +comes along with some additional assumptions about your board's layout. +The code in usb/ is not very portable at all right now; expect this to +change in the future, but for now, we're focusing on rolling out a +more complete backend. -Board portability is implemented by adding a header file to ./libmaple with the -name of the BOARD target, and then editing libmaple.h to add this file as an -option. - -A pin maple file should be added to ./notes describing the pin numbering - -Files to check by hand: -#   adc.c -#   adc.h -#   exc.c -#   exti.c -#   exti.h -#   flash.c -#   flash.h -#   gpio.c -#   gpio.h -#   libmaple_types.h -#   nvic.c -#   nvic.h -#   rcc.c -#   rcc.h -#   ring_buffer.h -#   rules.mk -#   spi.c --   spi.h -#   syscalls.c -#   systick.c -#   systick.h -#   timers.c -#   timers.h -#   usart.c -#   usart.h -#   util.c -#   util.h -#   libmaple.h -#   usb/* - -wirish/: -#   bits.h -#   boards.h -#   cxxabi-compat.cpp -#   ext_interrupts.c -#   ext_interrupts.h -#   HardwareTimer.cpp -#   HardwareTimer.h -#   io.h -#   main.cxx -#   Print.cpp -#   Print.h -#   pwm.c -#   pwm.h -#   rules.mk -#   time.c -#   time.h -#   usb_serial.cpp -#   usb_serial.h -#   wirish_analog.c -#   wirish.c -#   wirish_digital.c -#   wirish.h -#   wirish_math.cpp -#   wirish_math.h -#   wirish_shift.c -#   WProgram.h --   comm/ - - - -ADC Notes: -    only using ADC1? -    untested - -EXTI Notes: -    need to update huge table in comments? -    untested +A file should be added to ./notes describing the pin numbering of any +new board you add.  NVIC Notes: -    I don't think NVIC_ISER3 and NVIC_ICER3 actually exist?      Only CANBUS and USB OTG use interrupts above #63, but I updated the nvic code anyways  RCC Notes:      Added some clock stuff to all boards even though they aren't usable... blah.  SPI Notes: -    SPI3 is only in XL chips so didn't really handle that +    SPI3 is only in XL chips, so we don't handle that.  TIMER Notes: -    High-density devices add an advanced timer (TIMER8) and another normal one (TIMER5). -    TIMER6 and TIMER7 are much less useful. -    There is some partial progress towards adding timer5/timer8 functionality, -    but not much. This should probably all be rewritten.      The wirish timer implementation should be refactored to use pin numbers.  USART Notes: diff --git a/notes/timers.txt b/notes/timers.txt index 3f5b9f4..647e92e 100644 --- a/notes/timers.txt +++ b/notes/timers.txt @@ -1,82 +1,87 @@ +Timers +====== -Each timer (1-4) has 4 capture/compare channels (1-4). These are directly used -by PWM but have a ton of other possible functionality. The STM32 implementation -is particularly complicated with, eg, the ability to chain together timers - -Timer1 is an "advanced timer" with many more features. I think if we use just -the "Capture and compare interrupt", and enable MOE during initialization -everything will be ok. There are seperate Break, Update, and Trigger interrupts -as well that we will ignore for now. - -Timer2,Ch 3+4 are D0 and D1, which conflict with Serial2. USART should work -fine as long as pins aren't in output mode? and timers should work fine if -Serial2 isn't in use? - -Caveats ------------------------------------------------------------------------------- -There are probably subtle bugs with the way register settings get read in; eg, -it is often required to have the counter fully overflow before new settings -come into effect? -Getting really good timing is still an art, not a science here... usually you  -need to fiddle with an oscilloscope and the exact overflow/compare numbers to -get just the right time values. -Any other interrupts (SysTick, USB, Serial, etc) can blow away all the nice  -timing stuff. - -Misc Notes ------------------------------------------------------------------------------- -Implementation with case/switch in the interrupt handlers doesn't work; a lot -of the time multiple interrupt flags are active at the same time (or become -active?) +Medium-density chips have timers 1 through 4.  High- and XL-density +chips additionally have timers 5 through 8.  XL-density chips +additionally have timers 9--14, which we don't support yet. + +Timer Capabilities +------------------ + +Each of timers 1--4 has 4 capture/compare (C/C) channels (also numbered +1--4). These are directly used by PWM, but may serve other purposes as +well (including handling user-specified periodic interrupts). The +STM32 implementation is particularly featureful, with, e.g., the +ability to chain together timers. + +Timers 1 and 8 are an advanced timers, with many more features. +Wirish just uses just their capture/compare interrupts and enables MOE +during initialization, essentially treating them as general purpose +timers (like timers 2--5).  Advanced timers also have separate break, +update, and trigger interrupts that we only provide low-level +(i.e. libmaple proper) support for. + +Timers 6 and 7 are basic timers, without C/C channels.  They are still +useful for interrupts (via NVIC_TIMER6, NVIC_TIMER7 IRQs, which can +fire upon an update event), but they're most useful for controlling +periodic DAC output. + +Known Issues and Other Caveats +------------------------------ + +There are some conflicts between timer C/C outputs and USART 1 and 2 +TX/RX.  Wirish tries to handle this gracefully, but (as of 7 April +2011) not all the bugs are sorted yet.  In particular, if you call +HardwareSerial::disable(), then try to use PWM, the USART TX pins +don't cooperate. + +Resetting the prescaler or reload value only takes effect at the next +update event.  You can use timer_generate_update() to generate an +update event via software. + +Other interrupts (SysTick, USB, Serial, etc.) can interfere with +timing-critical applications.  If your program requires precise +timing, you should probably at least disable USB and SysTick.  Note +that this also disables the bootloader and stops millis()/micros() +from counting. + +Getting really good timing is a bit of an art.  If things don't work +at first, you need to fiddle with an oscilloscope and the exact +overflow/compare numbers to get precise behavior.  TODO ------------------------------------------------------------------------------- -- document carefully (eg, determine clock-wise and overflow-wise behavior for -  each function) -- track down and handle all pin conflicts -- implement the update interrupt as a "5th channel" -- "pulse in" stuff, both c and c++ -- function to read out CCR registers -- allow comparison output to the pin (a la PWM) -- additional modes and configuration (up, down, up/down, etc) - -Possible Wirish implementation ------------------------------------------------------------------------------- -Inspired by Timer1 Library for arduino -http://arduino.cc/pipermail/developers_arduino.cc/2010-June/002845.html +---- + +- Document more carefully (e.g., determine clock-wise and +  overflow-wise behavior for each function). -        class HardwareTimer { - -        public: - -            void pause(); -            void resume(); -            void setPrescaleFactor(uint8 factor); -            void setOverflow(uint16 val); // truncates to overflow -            void setCount(uint16 val);    // truncates to overflow -            uint16 getCount(); -            uint16 setPeriod(uint32 microseconds); // tries to set prescaler and overflow wisely; returns overflow -            void setMode(uint8 mode); -            void setCompare1(uint16 val); // truncates to overflow -            void setCompare2(uint16 val); // truncates to overflow -            void setCompare3(uint16 val); // truncates to overflow -            void setCompare4(uint16 val); // truncates to overflow -            void attachCompare1Interrupt(void (*f)(void)); -            void attachCompare2Interrupt(void (*f)(void)); -            void attachCompare3Interrupt(void (*f)(void)); -            void attachCompare4Interrupt(void (*f)(void)); -            void detachCompare1Interrupt(); -            void detachCompare2Interrupt(); -            void detachCompare3Interrupt(); -            void detachCompare4Interrupt(); -        }; - -        HardwareTimer Timer1 = HardwareTimer(1); -        HardwareTimer Timer2 = HardwareTimer(2); -        HardwareTimer Timer3 = HardwareTimer(3); -        HardwareTimer Timer4 = HardwareTimer(4); +- Track down and handle pin conflicts. + +- Input capture interface.  DON'T WRITE pulseIn() IN TERMS OF THIS. +  Do that as a simple, Arduino style implementation that just +  busy-waits and uses micros(), to allow a pulseIn() on arbitrary +  pins.  Eventually, expose the more precise/harder to use timer-based +  API via a convenience library. + +- Complementary outputs, with convenient break/dead time interface. + +- Additional modes (center-aligned PWM, one pulse mode, etc.) and +  count configuration (down, up/down). + +Alternative Wirish Implementations +---------------------------------- + +The current Wirish API is big and clunky.  Its inclusion by default +also threatens making everyone's sketches bigger unnecessarily.  We +need to deprecate the parts of it that are bad for 0.0.10, and remove +them when 0.1.0 comes out. + +Current implementation was inspired by Timer1 Library for Arduino: + +http://arduino.cc/pipermail/developers_arduino.cc/2010-June/002845.html  Here's one of the more standard libaries out there: +  http://www.arduino.cc/playground/Code/Timer1          void initialize(long microseconds=1000000); @@ -89,4 +94,3 @@ http://www.arduino.cc/playground/Code/Timer1          void disablePwm(char pin);          void attachInterrupt(void (*isr)(), long microseconds=-1);          void detachInterrupt(); - diff --git a/notes/usb.txt b/notes/usb.txt index 5e00354..9552b9f 100644 --- a/notes/usb.txt +++ b/notes/usb.txt @@ -1,3 +1,7 @@ +XXX +XXX This file may be out of date! +XXX +  [NOTE: this is a long term proposal. The current implementation just does a   2ms TIMEOUT] diff --git a/notes/vga.txt b/notes/vga.txt index d75281a..43b6830 100644 --- a/notes/vga.txt +++ b/notes/vga.txt @@ -7,8 +7,7 @@ gpio_write_bit() is about 360ns (2.78MHz)  Writing to GPIO?_BASE is about 60ns (16.6MHz -> 18MHz) -pwm write 0x0001 is about 30ns (33MHz) with prescaler as 1 (default) -pwm write 0x0001 is about 14ns (72MHz) with prescaler as 0 (!) +PWM write 0x0001 is about 14ns (72MHz) with prescaler as 0 (!)  VGA Timing  ------------------------------------------------------------------------------ @@ -34,9 +33,3 @@ Crude 640x480 directions:      11 lines front porch      2 lines Vsync (low)      31 lines back porch - -Currently, setting vs. clearing GPIO registers seems to take a different amount -of time? Or perhaps i'm not analyzing branching correctly. Regardless, if you -SET 100x times then UNSET on one line, then UNSET 100x then SET the next line, -the two changes in color will generally not line up.  - | 
