⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hal.sgml

📁 开放源码实时操作系统源码.
💻 SGML
📖 第 1 页 / 共 5 页
字号:
</programlisting>

<para>
This macro provides a busy loop delay for the given number of
microseconds. It is intended mainly for controlling hardware that
needs short delays between operations. Code which needs longer delays,
of the order of milliseconds, should instead use higher-level
functions such as <function>cyg_thread_delay</function>. The macro
implementation should be thread-safe. It can also be used in ISRs or
DSRs, although such usage is undesirable because of the impact on
interrupt and dispatch latency.
</para>

<para>
The macro should never delay for less than the specified amount of
time. It may delay for somewhat longer, although since the macro uses
a busy loop this is a waste of cpu cycles. Of course the code invoking
<function>HAL_DELAY_US</function> may get interrupted or timesliced,
in which case the delay may be much longer than intended. If this is
unacceptable then the calling code must take preventative action
such as disabling interrupts or locking the scheduler.
</para>

<para>
There are three main ways of implementating the macro:
</para>

<orderedlist>
  <listitem><para>
a counting loop, typically written in inline assembler, using an outer
loop for the microseconds and an inner loop that consumes
approximately 1us. This implementation is automatically thread-safe
and does not impose any dependencies on the rest of the system, for
example it does not depend on the system clock having been started.
However it assumes that the cpu clock speed is known at compile-time
or can be easily determined at run-time.
  </para></listitem>
  <listitem><para>
monitor one of the hardware clocks, usually the system clock. Usually
this clock ticks at a rate independent of the cpu so calibration is
easier. However the implementation relies on the system clock having
been started, and assumes that no other code is manipulating the clock
hardware. There can also be complications when the system clock wraps
around.
  </para></listitem>
  <listitem><para>
a combination of the previous two. The system clock is used during
system initialization to determine the cpu clock speed, and the result
is then used to calibrate a counting loop. This has the disadvantage
of significantly increasing the system startup time, which may be
unacceptable to some applications. There are also complications if the
system startup code normally runs with the cache disabled because the
instruction cache will greatly affect any calibration loop.
  </para></listitem>
</orderedlist>

</section>

<!-- =================================================================== -->

<section>
<title>Clock Frequency Definition</title>

<programlisting width=72>
CYGNUM_HAL_RTC_NUMERATOR
CYGNUM_HAL_RTC_DENOMINATOR
CYGNUM_HAL_RTC_PERIOD
</programlisting>

<para>
These macros are defined in the CDL for each platform and supply the
necessary parameters to specify the frequency at which the clock
interrupts. These parameters are usually found in the CDL definitions
for the target platform, or in some cases the CPU variant.
</para>

<para>
<literal>CYGNUM_HAL_RTC_NUMERATOR</literal> and
<literal>CYGNUM_HAL_RTC_DENOMINATOR</literal> specify the resolution
of the clock interrupt.  This resolution involves two separate values,
the numerator and the denominator. The result of dividing the
numerator by the denominator should correspond to the number of
nanoseconds between clock interrupts. For example a numerator of
1000000000 and a denominator of 100 means that there are 10000000
nanoseconds (or 10 milliseconds) between clock interrupts. Expressing
the resolution as a fraction minimizes clock drift even for
frequencies that cannot be expressed as a simple integer. For example
a frequency of 60Hz corresponds to a clock resolution of
16666666.66...  nanoseconds. This can be expressed accurately as
1000000000 over 60.
</para>

<para>
<literal>CYGNUM_HAL_RTC_PERIOD</literal> specifies the exact value
used to initialize the clock hardware, it is the value passed as a
parameter to <literal>HAL_CLOCK_INITIALIZE()</literal> and
<literal>HAL_CLOCK_RESET()</literal>. The exact meaning of the value
and the range of legal values therefore depends on the target
hardware, and the hardware documentation should be consulted for
further details.
</para>

<para>
The default values for these macros in all HALs are calculated to give
a clock interrupt frequency of 100Hz, or 10ms between interrupts. To
change the clock frequency, the period needs to be changed, and the
resolution needs to be adjusted accordingly. As an example consider
the i386 PC target. The default values for these macros are:
</para>

<programlisting width=72>
CYGNUM_HAL_RTC_NUMERATOR     1000000000
CYGNUM_HAL_RTC_DENOMINATOR   100
CYGNUM_HAL_RTC_PERIOD        11932
</programlisting>

<para>
To change to, say, a 200Hz clock the period needs to be halved to
5966, and to compensate the denominator needs to be doubled to 200. To
change to a 1KHz interrupt rate change the period to 1193 and the
denominator to 1000.
</para>

<para>
Some HALs make this process a little easier by deriving the period
arithmetically from the denominator. This calculation may also involve
the CPU clock frequency and possibly other factors. For example in the
ARM AT91 variant HAL the period is defined by the following
expression:
</para>

<programlisting width=72>
((CYGNUM_HAL_ARM_AT91_CLOCK_SPEED/32) / CYGNUM_HAL_RTC_DENOMINATOR)
</programlisting>

<para>
In this case it is not necessary to change the period at all, just
change the denominator to select the desired clock frequency. However,
note that for certain choices of frequency, rounding errors in this
calculation may result in a small clock drift over time. This is
usually negligible, but if perfect accuracy is required, it may be
necessary to adjust the frequency or period by hand.
</para>

</section>


</section>

<!-- }}} -->
<!-- {{{ Input and Output -->

<SECTION id="hal-input-and-output">
<TITLE>HAL I/O</TITLE>

<PARA>
This section contains definitions for supporting access
to device control registers in an architecture neutral
fashion.
</PARA>

<para>
These definitions are normally found in the header file
<FILENAME>cyg/hal/hal_io.h</FILENAME>.  This file itself contains
macros that are generic to the architecture. If there are variant or
platform specific IO access macros then these will be found in
<filename>cyg/hal/var_io.h</filename> and
<filename>cyg/hal/plf_io.h</filename> in the variant or platform HALs
respectively. These files are include automatically by this header, so
need not be included explicitly.
</para>

<para>
This header (or more likely <filename>cyg/hal/plf_io.h</filename>) also
defines the PCI access macros. For more information on these see <xref
linkend="pci-library-reference">.
</para>

<!-- =================================================================== -->

<SECTION>
<TITLE>Register address</TITLE>

<PROGRAMLISTING>
HAL_IO_REGISTER
</PROGRAMLISTING>

<PARA>
This type is used to store the address of an I/O register. It will
normally be a memory address, an integer port address or an offset
into an I/O space. More complex architectures may need to code an
address space plus offset pair into a single word, or may represent it
as a structure.
</PARA>

<PARA>
Values of variables and constants of this type will usually be
supplied by configuration mechanisms or in target specific headers.
</PARA>

</SECTION>

<!-- =================================================================== -->

<SECTION>
<TITLE>Register read</TITLE>

<PROGRAMLISTING>
HAL_READ_XXX( register, value )
HAL_READ_XXX_VECTOR( register, buffer, count, stride )
</PROGRAMLISTING>

<PARA>
These macros support the reading of I/O registers in various
sizes. The <replaceable>XXX</replaceable> component of the name may be
<literal>UINT8</literal>, <literal>UINT16</literal>,
<literal>UINT32</literal>.
</PARA>

<PARA>
<FUNCTION>HAL_READ_XXX()</FUNCTION> reads the appropriately sized
value from the register and stores it in the variable passed as the
second argument.
</PARA>

<PARA>
<FUNCTION>HAL_READ_XXX_VECTOR()</FUNCTION> reads
<parameter>count</parameter> values of the appropriate size into
<parameter>buffer</parameter>. The <parameter>stride</parameter>
controls how the pointer advances through the register space. A stride
of zero will read the same register repeatedly, and a stride of one
will read adjacent registers of the given size. Greater strides will
step by larger amounts, to allow for sparsely mapped registers for
example.</PARA>
</SECTION>

<!-- =================================================================== -->

<SECTION>
<TITLE>Register write</TITLE>

<PROGRAMLISTING>
HAL_WRITE_XXX( register, value )
HAL_WRITE_XXX_VECTOR( register, buffer,count, stride )
</PROGRAMLISTING>

<PARA>
These macros support the writing of I/O registers in various
sizes. The <replaceable>XXX</replaceable> component of the name may be
<LITERAL>UINT8</LITERAL>, <LITERAL>UINT16</LITERAL>,
<LITERAL>UINT32</LITERAL>.
</PARA>

<PARA>
<FUNCTION>HAL_WRITE_XXX()</FUNCTION> writes
the appropriately sized value from the variable passed as the second argument
stored it in the register.</PARA>
<PARA><FUNCTION>HAL_WRITE_XXX_VECTOR()</FUNCTION> writes
<parameter>count</parameter> values of the appropriate size from <parameter>
buffer</parameter>. The <parameter>stride</parameter> controls
how the pointer advances through the register space. A stride of
zero will write the same register repeatedly, and a stride of one
will write adjacent registers of the given size. Greater strides
will step by larger amounts, to allow for sparsely mapped registers
for example.</PARA>
</SECTION>
</SECTION>

<!-- }}} -->
<!-- {{{ Cache Control -->

<SECTION id="hal-cache-control">
<TITLE>Cache Control</TITLE>

<PARA>This section contains definitions for supporting control
of the caches on the CPU.
</PARA>

<para>
These definitions are usually found in the header file
<FILENAME>cyg/hal/hal_cache.h</FILENAME>.  This file may be defined in
the architecture, variant or platform HAL, depending on where the
caches are implemented for the target. Often there will be a generic
implementation of the cache control macros in the architecture HAL
with the ability to override or undefine them in the variant or
platform HAL. Even when the implementation of the cache macros is in
the architecture HAL, the cache dimensions will be defined in the
variant or platform HAL. As with other files, the variant or platform
specific definitions are usually found in
<filename>cyg/hal/var_cache.h</filename> and
<filename>cyg/hal/plf_cache.h</filename> respectively.  These files
are include automatically by this header, so need not be included
explicitly.
</para>

<PARA>
There are versions of the macros defined here for both the Data and
Instruction caches. these are distinguished by the use of either
<literal>DCACHE</literal> or <literal>ICACHE</literal> in the macro
names. Some architectures have a unified cache, where both data and
instruction share the same cache. In these cases the control macros
use <literal>UCACHE</literal> and the <literal>DCACHE</literal> and
<literal>ICACHE</literal> macros will just be calls to the
<literal>UCACHE</literal> version. In the following descriptions,
<literal>XCACHE</literal> is used to stand for any of these. Where
there are issues specific to a particular cache, this will be
explained in the text.
</PARA>

<PARA>
There might be target specific restrictions on the use of some of the
macros which it is the user's responsibility to comply with. Such
restrictions are documented in the header file with the macro
definition.
</PARA>

<PARA>
Note that destructive cache macros should be used with caution.
Preceding a cache invalidation with a cache synchronization is not
safe in itself since an interrupt may happen after the synchronization
but before the invalidation. This might cause the state of dirty data
lines created during the interrupt to be lost.
</PARA>

<PARA>
Depending on the architecture's capabilities, it may be possible to
temporarily disable the cache while doing the synchronization and
invalidation which solves the problem (no new data would be cached
during an interrupt). Otherwise it is necessary to disable interrupts
while manipulating the cache which may take a long time.
</PARA>

<PARA>
Some platform HALs now support a pair of cache state query
macros: <function>HAL_ICACHE_IS_ENABLED( x )</function> and
<function>HAL_DCACHE_IS_ENABLED( x )</function> which set the argument
to true if the instruction or data cache is enabled,
respectively. Like most cache control macros, these are optional,
because the capabilities of different targets and boards can vary
considerably. Code which uses them, if it is to be considered
portable, should test for their existence first by means of
<literal>#ifdef</literal>.  Be sure to include
<filename>&lt;cyg/hal/hal_cache.h&gt;</filename> in order to do this
test and (maybe) use the macros.
</PARA>

<!-- =================================================================== -->

<SECTION>
<TITLE>Cache Dimensions</TITLE>

<PROGRAMLISTING>
HAL_XCACHE_SIZE
HAL_XCACHE_LINE_SIZE
HAL_XCACHE_WAYS
HAL_XCACHE_SETS
</PROGRAMLISTING>
<PARA>
These macros define the size and dimensions of the Instruction
and Data caches.
</PARA>

<VARIABLELIST>
  <VARLISTENTRY>
    <TERM>HAL_XCACHE_SIZE 	</TERM>
    <LISTITEM>
      <PARA>Defines the total size of the cache in bytes.</PARA>
    </LISTITEM>
  </VARLISTENTRY>

  <VARLISTENTRY>
    <TERM>HAL_XCACHE_LINE_SIZE 	</TERM>
    <LISTITEM>
      <PARA>Defines the cache line size in bytes.</PARA>
    </LISTITEM>
  </VARLISTENTRY>
  
  <VARLISTENTRY>
    <TERM>HAL_XCACHE_WAYS 	</TERM>
    <LISTITEM>
      <PARA>
      Defines the number of ways in each set and defines its level
      of associativity. This would be 1 for a direct mapped
      cache, 2 for a 2-way cache, 4 for 4-way and so on.
      </PARA>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -