blob: 3a4abf9206d1cf489746a039468dc4b0c2c4a0af [file] [log] [blame]
<!--
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 &mdash; 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[] = &quot;Hello, world\n&quot;;
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[] = &quot;Hello, world\n&quot;;
</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[] = &quot;Hello, world\n&quot;;
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>&#169; Copyright 2023, The Apache Software Foundation.</p>
</div>
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>