| <!-- |
| Documentation/_templates/layout.html |
| |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. The |
| ASF licenses this file to you 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. |
| --> |
| |
| |
| |
| <!DOCTYPE html> |
| <html class="writer-html5" lang="en"> |
| <head> |
| <meta charset="utf-8" /><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" /> |
| |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
| <title>Keeping constants in program memory — NuttX latest documentation</title> |
| <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css" /> |
| <link rel="stylesheet" type="text/css" href="../../../_static/css/theme.css" /> |
| <link rel="stylesheet" type="text/css" href="../../../_static/copybutton.css" /> |
| <link rel="stylesheet" type="text/css" href="../../../_static/sphinx_collapse.css" /> |
| <link rel="stylesheet" type="text/css" href="../../../_static/design-style.1e8bd061cd6da7fc9cf755528e8ffc24.min.css" /> |
| <link rel="stylesheet" type="text/css" href="../../../_static/custom.css" /> |
| |
| |
| <link rel="shortcut icon" href="../../../_static/favicon.ico"/> |
| <script src="../../../_static/jquery.js"></script> |
| <script src="../../../_static/_sphinx_javascript_frameworks_compat.js"></script> |
| <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> |
| <script src="../../../_static/doctools.js"></script> |
| <script src="../../../_static/sphinx_highlight.js"></script> |
| <script src="../../../_static/clipboard.min.js"></script> |
| <script src="../../../_static/copybutton.js"></script> |
| <script src="../../../_static/design-tabs.js"></script> |
| <script src="../../../_static/js/theme.js"></script> |
| <link rel="index" title="Index" href="../../../genindex.html" /> |
| <link rel="search" title="Search" href="../../../search.html" /> |
| <link rel="next" title="Notes on AVR context switch" href="context-switch-notes.html" /> |
| <link rel="prev" title="Two Wire Interface in AVR DA/DB" href="../avrdx/docs/twi.html" /> |
| </head> |
| |
| <body class="wy-body-for-nav"> |
| <div class="wy-grid-for-nav"> |
| <nav data-toggle="wy-nav-shift" class="wy-nav-side"> |
| <div class="wy-side-scroll"> |
| <div class="wy-side-nav-search" > |
| |
| <a href="../../../index.html" class="icon icon-home"> NuttX |
| |
| |
| |
| </a> |
| |
| <!-- this version selector is quite ugly, should be probably replaced by something |
| more modern --> |
| |
| <div class="version-selector"> |
| <select onchange="javascript:location.href = this.value;"> |
| |
| <option value="../../../../latest" selected="selected">latest</option> |
| |
| <option value="../../../../10.0.0" >10.0.0</option> |
| |
| <option value="../../../../10.0.1" >10.0.1</option> |
| |
| <option value="../../../../10.1.0" >10.1.0</option> |
| |
| <option value="../../../../10.2.0" >10.2.0</option> |
| |
| <option value="../../../../10.3.0" >10.3.0</option> |
| |
| <option value="../../../../11.0.0" >11.0.0</option> |
| |
| <option value="../../../../12.0.0" >12.0.0</option> |
| |
| <option value="../../../../12.1.0" >12.1.0</option> |
| |
| <option value="../../../../12.2.0" >12.2.0</option> |
| |
| <option value="../../../../12.2.1" >12.2.1</option> |
| |
| <option value="../../../../12.3.0" >12.3.0</option> |
| |
| <option value="../../../../12.4.0" >12.4.0</option> |
| |
| <option value="../../../../12.5.0" >12.5.0</option> |
| |
| <option value="../../../../12.5.1" >12.5.1</option> |
| |
| <option value="../../../../12.6.0" >12.6.0</option> |
| |
| <option value="../../../../12.7.0" >12.7.0</option> |
| |
| <option value="../../../../12.8.0" >12.8.0</option> |
| |
| <option value="../../../../12.9.0" >12.9.0</option> |
| |
| <option value="../../../../12.10.0" >12.10.0</option> |
| |
| <option value="../../../../12.11.0" >12.11.0</option> |
| |
| </select> |
| </div> |
| |
| |
| <div role="search"> |
| <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> |
| <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" /> |
| <input type="hidden" name="check_keywords" value="yes" /> |
| <input type="hidden" name="area" value="default" /> |
| </form> |
| </div> |
| |
| </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> |
| <p class="caption" role="heading"><span class="caption-text">Table of Contents</span></p> |
| <ul class="current"> |
| <li class="toctree-l1"><a class="reference internal" href="../../../index.html">Home</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="../../../introduction/index.html">Introduction</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="../../../quickstart/index.html">Getting Started</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="../../../contributing/index.html">Contributing</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="../../../introduction/inviolables.html">The Inviolable Principles of NuttX</a></li> |
| <li class="toctree-l1 current"><a class="reference internal" href="../../index.html">Supported Platforms</a><ul class="current"> |
| <li class="toctree-l2"><a class="reference internal" href="../../arm/index.html">ARM</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="../../arm64/index.html">ARM64</a></li> |
| <li class="toctree-l2 current"><a class="reference internal" href="../index.html">Microchip AVR</a><ul class="current"> |
| <li class="toctree-l3"><a class="reference internal" href="../at32uc3/index.html">Microchip AT32UC3</a></li> |
| <li class="toctree-l3"><a class="reference internal" href="../at90usb/index.html">Microchip AT90USB</a></li> |
| <li class="toctree-l3"><a class="reference internal" href="../atmega/index.html">Microchip Atmega</a></li> |
| <li class="toctree-l3"><a class="reference internal" href="../avrdx/index.html">Microchip DA/DB family</a></li> |
| <li class="toctree-l3 current"><a class="current reference internal" href="#">Keeping constants in program memory</a><ul> |
| <li class="toctree-l4"><a class="reference internal" href="#introduction">Introduction</a></li> |
| <li class="toctree-l4"><a class="reference internal" href="#solution-of-the-problem">Solution of the problem</a></li> |
| <li class="toctree-l4"><a class="reference internal" href="#problem-of-the-solution">Problem of the solution</a></li> |
| <li class="toctree-l4"><a class="reference internal" href="#constants-in-program-memory">Constants in program memory</a><ul> |
| <li class="toctree-l5"><a class="reference internal" href="#using-progmem">Using PROGMEM</a></li> |
| </ul> |
| </li> |
| <li class="toctree-l4"><a class="reference internal" href="#using-memx-flashx">Using __memx/__flashx</a></li> |
| <li class="toctree-l4"><a class="reference internal" href="#using-memory-mapped-flash">Using memory-mapped flash</a></li> |
| </ul> |
| </li> |
| <li class="toctree-l3"><a class="reference internal" href="context-switch-notes.html">Notes on AVR context switch</a></li> |
| </ul> |
| </li> |
| <li class="toctree-l2"><a class="reference internal" href="../../ceva/index.html">CEVA</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="../../hc/index.html">HC</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="../../mips/index.html">MIPS</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="../../misco/index.html">Misoc</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="../../or1k/index.html">OpenRISC</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="../../renesas/index.html">Renesas</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="../../risc-v/index.html">RISC-V</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="../../sim/index.html">Simulators</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="../../sim/network_linux.html">Network Support on Linux</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="../../sim/network_vpnkit.html">Network support with VPNKit</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="../../sparc/index.html">SPARC</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="../../tricore/index.html">TriCore</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="../../x86/index.html">Intel 80x86</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="../../x86_64/index.html">Intel 80x86_64</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="../../xtensa/index.html">Xtensa</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="../../z16/index.html">Z16</a></li> |
| <li class="toctree-l2"><a class="reference internal" href="../../z80/index.html">Z80</a></li> |
| </ul> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="../../../components/index.html">OS Components</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="../../../applications/index.html">Applications</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="../../../implementation/index.html">Implementation Details</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="../../../reference/index.html">API Reference</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="../../../faq/index.html">FAQ</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="../../../debugging/index.html">Debugging</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="../../../guides/index.html">Guides</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="../../../standards/index.html">Standards</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="../../../glossary.html">Glossary</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="../../../logos/index.html">NuttX Logos</a></li> |
| <li class="toctree-l1"><a class="reference internal" href="../../../_tags/tagsindex.html">Tags</a></li> |
| </ul> |
| |
| </div> |
| </div> |
| </nav> |
| |
| <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" > |
| <i data-toggle="wy-nav-top" class="fa fa-bars"></i> |
| <a href="../../../index.html">NuttX</a> |
| </nav> |
| |
| <div class="wy-nav-content"> |
| <div class="rst-content"> |
| <div role="navigation" aria-label="Page navigation"> |
| <ul class="wy-breadcrumbs"> |
| <li><a href="../../../index.html" class="icon icon-home" aria-label="Home"></a></li> |
| <li class="breadcrumb-item"><a href="../../index.html">Supported Platforms</a></li> |
| <li class="breadcrumb-item"><a href="../index.html">Microchip AVR</a></li> |
| <li class="breadcrumb-item active">Keeping constants in program memory</li> |
| <li class="wy-breadcrumbs-aside"> |
| <a href="https://github.com/apache/nuttx/blob/master/Documentation/platforms/avr/common/constants-in-progmem.rst" class="fa fa-github"> Edit on GitHub</a> |
| </li> |
| </ul> |
| <hr/> |
| </div> |
| <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> |
| <div itemprop="articleBody"> |
| |
| <section id="keeping-constants-in-program-memory"> |
| <h1>Keeping constants in program memory<a class="headerlink" href="#keeping-constants-in-program-memory" title="Permalink to this heading"></a></h1> |
| <p>By default, all constants in a program running on AVR device are copied |
| into RAM. This document describes the reasons for doing that and options |
| to keep them in program memory.</p> |
| <section id="introduction"> |
| <h2>Introduction<a class="headerlink" href="#introduction" title="Permalink to this heading"></a></h2> |
| <p>AVR architecture is a Harvard architecture, program and data memories are |
| accessed over separate buses with their own address spaces. While this approach |
| has its advantages, it does not match well with C programs which expect |
| to be able to access everything in the same way. (That is - using |
| the same instructions.) In fact, unless some measures are taken, C program |
| is completely unable to access initialized variables.</p> |
| <p>Consider this variable declaration and function call:</p> |
| <div class="highlight-none notranslate"><div class="highlight"><pre><span></span>const char hello[] = "Hello, world\n"; |
| printf(hello); |
| </pre></div> |
| </div> |
| <p>When this code is compiled, the string is stored somewhere within |
| the program and uploaded to the program memory (flash.) Pointer |
| variable <code class="docutils literal notranslate"><span class="pre">hello</span></code> then contains address of the string. Call |
| to <code class="docutils literal notranslate"><span class="pre">printf</span></code> receives this address and attempts to load and process |
| characters of this string - on AVR, indirect load from memory |
| instructions would be used for that.</p> |
| <p>On a von Neumann architecture, which has single address space |
| for both program and data, this would pose no problem. Since |
| the program memory is part of the overall address space, the load |
| instructions can reach the data contained within it. This is, |
| however, not the case for AVR. Anything stored |
| in program memory is inaccessible for regular load instruction |
| and the <code class="docutils literal notranslate"><span class="pre">printf</span></code> call would fail.</p> |
| </section> |
| <section id="solution-of-the-problem"> |
| <h2>Solution of the problem<a class="headerlink" href="#solution-of-the-problem" title="Permalink to this heading"></a></h2> |
| <p>AVR provides instructions that are able to load data from program memory. |
| These instructions can be used to copy all the constants into the RAM, |
| the copy is then available to regular load instructions and the program |
| can work correctly.</p> |
| <p>Internally, variable <code class="docutils literal notranslate"><span class="pre">hello</span></code> is altered to contain address of the copy |
| of the string with the data address space . It can be passed freely into |
| <code class="docutils literal notranslate"><span class="pre">printf</span></code> or any other function.</p> |
| <p>All that is needed is a code that performs that copy and that code |
| is present in NuttX. It is executed automatically at program startup. |
| If the application is being developed for a supported board, everything |
| happens automatically. (If the application is being developed for a custom board, the board’s |
| linker script only needs to provide some variables - common architecture |
| code then takes care of the rest.)</p> |
| <p>In other words - by default, any application running on NuttX is able |
| to freely pass any variable to any NuttX interface.</p> |
| </section> |
| <section id="problem-of-the-solution"> |
| <h2>Problem of the solution<a class="headerlink" href="#problem-of-the-solution" title="Permalink to this heading"></a></h2> |
| <p>As described, this solution works reliably and correctly. However, there |
| is a significant cost to it - it consumes RAM, which is a limited resource. |
| For example, one of the supported chips is ATmega128 featuring 4kB of SRAM. |
| Even a simple program will quickly consume significant part of it, |
| especially if it contains a lot of strings.</p> |
| </section> |
| <section id="constants-in-program-memory"> |
| <h2>Constants in program memory<a class="headerlink" href="#constants-in-program-memory" title="Permalink to this heading"></a></h2> |
| <p>As its name suggests, this document describes techniques used |
| to make the program work without the need to copy constants to RAM.</p> |
| <section id="using-progmem"> |
| <h3>Using PROGMEM<a class="headerlink" href="#using-progmem" title="Permalink to this heading"></a></h3> |
| <p>PROGMEM is a macro defined GNU’s C library for AVR architecture. |
| It translates to a qualifier that instructs the compiler not to move |
| the variable from program memory to RAM. It is used like this:</p> |
| <div class="highlight-none notranslate"><div class="highlight"><pre><span></span>const uint8_t values[4] PROGMEM = { 0, 2, 4, 6 }; |
| </pre></div> |
| </div> |
| <p>When the variable is declared this way, it will not be copied to RAM |
| by the initialization code. |
| It cannot be used by normal means in this state though. As a pointer, |
| it holds address of data in program memory. This makes anything like |
| the following impossible:</p> |
| <div class="highlight-none notranslate"><div class="highlight"><pre><span></span>function(values); |
| </pre></div> |
| </div> |
| <p>The issue here is described at the beginning of the document. Contents |
| of <code class="docutils literal notranslate"><span class="pre">values</span></code> is not present in the RAM and therefore cannot be reached |
| using regular load instructions.</p> |
| <p>Instead, the compiler needs to be explicitly instructed to read from |
| program memory. The C library provides functions to achieve that. Those |
| functions will accept the pointer to program memory and are at least |
| partially written in AVR assembly, making sure that LPM (load from |
| program memory) instructions are used.</p> |
| <p>Main drawback of this method manifests itself when a function needs |
| to be able to accept a parameter which may be stored either in RAM |
| or in the program memory. It either needs to have an additional parameter |
| to distinguish where to read from, or the function needs to be provided |
| in two variants. (Or even more variants if it accepts more than one |
| such parameter.)</p> |
| <p>This is unsupported in NuttX altogether. The application may use variables |
| declared with PROGMEM qualifier freely but must not pass them to any NuttX |
| interface.</p> |
| </section> |
| </section> |
| <section id="using-memx-flashx"> |
| <h2>Using __memx/__flashx<a class="headerlink" href="#using-memx-flashx" title="Permalink to this heading"></a></h2> |
| <p>An example usage of the <code class="docutils literal notranslate"><span class="pre">__memx</span></code> qualifier would be:</p> |
| <div class="highlight-none notranslate"><div class="highlight"><pre><span></span>const __memx char hello[] = "Hello, world\n"; |
| </pre></div> |
| </div> |
| <p>In this context, the qualifier has the same same meaning as PROGMEM above, |
| the variable will not be copied into the RAM by the initialization code. |
| (<code class="docutils literal notranslate"><span class="pre">__flashx</span></code> has the same meaning but this qualifier is a feature of relatively |
| new - relatively of when this document is written - release of GCC |
| and is not used in NuttX.)</p> |
| <p>The meaning changes when the variable is used, for example:</p> |
| <div class="highlight-none notranslate"><div class="highlight"><pre><span></span>void function(const __memx char *arg) |
| </pre></div> |
| </div> |
| <p>In this case, <code class="docutils literal notranslate"><span class="pre">__memx</span></code> signals the compiler that the pointer may |
| be dereferenced to either the data or the program memory address space. |
| That needs to be determined during run-time.</p> |
| <p>Internally, this is achieved by extending the pointer to 24-bit length; |
| this also accommodates devices with more than 64kB program memory. |
| Most significant bit in the pointer then determines which address space |
| needs to be used when dereferencing the pointer. This bit is set |
| for data address space and cleared for program memory address space.</p> |
| <p>There is a significant run-time cost of using this method. Essentially, |
| every memory access to a variable with this qualifier is replaced with |
| a function call that determines memory type and reads from appropriate |
| address space. This call can take around 15 clock cycles for single |
| byte read. It is also entirely possible that unoptimized call |
| to eg. strlen will call this function for each byte in the string.</p> |
| <p>NuttX supports these qualifiers using IOBJ and IPTR macros like this:</p> |
| <div class="highlight-none notranslate"><div class="highlight"><pre><span></span>const IOBJ char hello[] = "Hello, world\n"; |
| void function(const IPTR char *arg); |
| </pre></div> |
| </div> |
| <p><code class="docutils literal notranslate"><span class="pre">IOBJ</span></code> denotes variable that should remain in program memory. |
| It currently translates to <code class="docutils literal notranslate"><span class="pre">__memx</span></code> but may eventually be switched |
| to <code class="docutils literal notranslate"><span class="pre">__flashx</span></code>. <code class="docutils literal notranslate"><span class="pre">IPTR</span></code> always translates to <code class="docutils literal notranslate"><span class="pre">__memx</span></code>.</p> |
| <p>This method of keeping constants in program memory |
| has a very limited support in NuttX. Essentially, it was |
| added as a debugging feature to support format strings with debug |
| messages. What this means is that functions related to logging |
| tend to have the <code class="docutils literal notranslate"><span class="pre">IPTR</span></code> qualifier in their declaration. Other functions |
| don’t - most interactions with the kernel will not accept these pointers.</p> |
| <p>Note that both <code class="docutils literal notranslate"><span class="pre">IOBJ</span></code> and <code class="docutils literal notranslate"><span class="pre">IPTR</span></code> need to be activated by |
| <span class="menuselection">System Type ‣ Mark const variables with __memx</span>. |
| If this configuration option is not set, both macros are defined |
| to be empty and all strings will be copied to RAM (performance penalty |
| discussed above is therefore removed as well.)</p> |
| </section> |
| <section id="using-memory-mapped-flash"> |
| <h2>Using memory-mapped flash<a class="headerlink" href="#using-memory-mapped-flash" title="Permalink to this heading"></a></h2> |
| <p>Newer AVR devices - tinyAVR and AVR DA/DB family - have their program |
| memory mapped into upper 32kB half of data memory address space. |
| (If the program memory size exceeds 32kB, only a 32kB-sized window |
| is mapped. This is controlled by NVM peripheral within the chip. |
| On current chips, the top window is mapped by default.)</p> |
| <p>This can be leveraged in a way that makes these AVR devices behave |
| as a von Neumann architecture. With proper configuration in a linker |
| script, all constants can be placed into the mapped program memory |
| region where they will be accessible for both load from program memory |
| instructions and load from data address space instructions.</p> |
| <p>As long as these constants fit into the 32kB window, this is a best |
| available option on devices that support it. It combines advantages |
| of all previous options and doesn’t have any of their drawbacks. |
| The performance penalty is negligible (flash read is few cycles slower |
| than RAM read), RAM is not consumed and all variables are fully |
| available to be used as parameters for any kernel interface.</p> |
| <p>Unlike previous options, using this one is fully controlled by board’s |
| linker script. The linker script needs to place the constants |
| (eg. <code class="docutils literal notranslate"><span class="pre">rodata</span></code> section) to appropriate memory location.</p> |
| <p>Despite that, there is still a configuration option |
| <span class="menuselection">System Type ‣ Use memory-mapped access to flash</span>, |
| which is selected by default on devices that support this method |
| of not copying data from program memory to RAM. Setting it unlocks |
| additional configuration options |
| <span class="menuselection">Size of .rodata FLMAP section</span> and |
| <span class="menuselection">Offset of .rodata FLMAP section</span> which may be used |
| to further configure section sizes. Note that these values are |
| only made available to the linker and board’s linker script needs |
| to be designed to obey them.</p> |
| <p>To have these configuration options available, the board needs |
| to select <code class="docutils literal notranslate"><span class="pre">AVR_HAVE_BOARD_FLMAP</span></code> in its configuration. It declares |
| that its linker script will obey <code class="docutils literal notranslate"><span class="pre">__RODATA_SIZE__</span></code> and |
| <code class="docutils literal notranslate"><span class="pre">__RODATA_OFFSET__</span></code> symbols (which are set by the above-mentioned |
| configuration options.)</p> |
| <p>See the linker script of <a class="reference internal" href="../avrdx/boards/breadxavr/index.html#breadxavr-board"><span class="std std-ref">AVR128DA28 on breadboard</span></a> for an example.</p> |
| </section> |
| </section> |
| |
| |
| </div> |
| </div> |
| <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer"> |
| <a href="../avrdx/docs/twi.html" class="btn btn-neutral float-left" title="Two Wire Interface in AVR DA/DB" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a> |
| <a href="context-switch-notes.html" class="btn btn-neutral float-right" title="Notes on AVR context switch" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a> |
| </div> |
| |
| <hr/> |
| |
| <div role="contentinfo"> |
| <p>© Copyright 2023, The Apache Software Foundation.</p> |
| </div> |
| |
| |
| |
| </footer> |
| </div> |
| </div> |
| </section> |
| </div> |
| <script> |
| jQuery(function () { |
| SphinxRtdTheme.Navigation.enable(true); |
| }); |
| </script> |
| |
| </body> |
| </html> |