...
One
...
of
...
the
...
largest
...
OS
...
data
...
structures
...
is
...
the
...
vector
...
table,
...
g_irqvector
...
[]
...
.
...
This
...
is
...
the
...
table
...
that
...
holds
...
the
...
vector
...
information
...
when
...
irq_attach()
...
is
...
called
...
and
...
used
...
to
...
dispatch
...
interrupts
...
by
...
irq_dispatch()
...
.
...
Recent
...
changes
...
have
...
made
...
that
...
table
...
even
...
larger,
...
for
...
32-bit
...
arm
...
the
...
size
...
of
...
that
...
table
...
is
...
given
...
by:
Code Block |
---|
nbytes = number_of_interrupts * (2 * sizeof(void *)) |
...
For a 32-bit ARM like the STM32 with, say, 100 interrupt vectors, this size would be 800 bytes of memory. That is not a lot for high-end MCUs with a lot of RAM memory, but could be a show stopper for MCUs with minimal RAM.
...
Two
...
approaches
...
for
...
reducing
...
the
...
size
...
of
...
the
...
vector
...
tables
...
are
...
described
...
below.
...
Both
...
depend
...
on
...
the
...
fact
...
that
...
not
...
all
...
interrupts
...
are
...
used
...
on
...
a
...
given
...
MCU.
...
Most
...
of
...
the
...
time,
...
the
...
majority
...
of
...
entries
...
in
...
g_irqvector
...
[]
...
are
...
zero
...
because
...
only
...
a
...
small
...
number
...
of
...
interrupts
...
are
...
actually
...
attached
...
and
...
enabled
...
by
...
the
...
application.
...
If
...
you
...
know
...
that
...
certain
...
IRQ
...
numbers
...
are
...
not
...
going
...
to
...
be
...
used,
...
then
...
it
...
is
...
possible
...
to
...
filter
...
those
...
out
...
and
...
reduce
...
the
...
size
...
to
...
the
...
number
...
of
...
supported
...
interrupts.
For example, if the actual number of interrupts used were 20, the the above requirement would go from 800 bytes to 160 bytes.
Software IRQ Remapping
...
...
[On
...
March
...
3,
...
2017,
...
support
...
for
...
this
...
"Software
...
IRQ
...
Remapping"
...
as
...
included
...
in
...
the
...
NuttX
...
repository.]
...
One
...
of
...
the
...
simplest
...
way
...
of
...
reducing
...
the
...
size
...
of
...
g_irqvector
...
[
...
]
...
would
...
be
...
to
...
remap
...
the
...
large
...
set
...
of
...
physcial
...
interrupt
...
vectors
...
into
...
a
...
much
...
small
...
set
...
of
...
interrupts
...
that
...
are
...
actually
...
used.
...
For
...
the
...
sake
...
of
...
discussion,
...
let's
...
imagine
...
two
...
new
...
configuration
...
settings:
CONFIG_ARCH_MINIMAL_VECTORTABLE
: Enables IRQ mappingCONFIG_ARCH_NUSER_INTERRUPTS
: The number of IRQs after mapping.
...
Code Block |
---|
#ifdef CONFIG_ARCH_MINIMAL_VECTORTABLE struct irq_info_s g_irqvector[CONFIG_ARCH_NUSER_INTERRUPTS]; #else struct irq_info_s g_irqvector[NR_IRQS]; #endif |
The
...
g_irqvector
...
[]
...
table
...
is
...
accessed
...
in
...
only
...
three
...
places:
irq_attach()
irq_attach()
receives the physical vector number along with the information needed later to dispatch interrupts:
...
Code Block |
---|
#ifdef CONFIG_ARCH_MINIMAL_VECTORTABLE int ndx = g_irqmap[irq]; #else int ndx = irq; #endif |
where
...
up_mapirq
...
[]
...
is
...
an
...
array
...
indexed
...
by
...
the
...
physical
...
interrupt
...
vector
...
number
...
and
...
contains
...
the
...
new,
...
mapped
...
interrupt
...
vector
...
table
...
index.
...
This
...
array
...
must
...
be
...
provided
...
by
...
platform-specific
...
code.
...
...
irq_attach()
...
would
...
this
...
use
...
this
...
index
...
to
...
set
...
the
...
g_irqvector
...
[]
.
Code Block |
---|
g_irqvector[ndx].handler = isr; g_irqvector[ndx].arg = arg; |
...
Code Block |
---|
vector = g_irqvector[ndx].handler; arg = g_irqvector[ndx].arg; |
Code Block |
vector(irq, context, arg); |
irq_initialize()
...
...
irq_initialize()
...
:
...
simply
...
set
...
the
...
g_irqvector
...
[]
...
table
...
a
...
known
...
state
...
on
...
power-up.
...
It
...
would
...
only
...
have
...
to
...
distinquish
...
the
...
difference
...
in
...
sizes.
Code Block |
---|
#ifdef CONFIG_ARCH_MINIMAL_VECTORTABLE # define TAB_SIZE CONFIG_ARCH_NUSER_INTERRUPTS #else # define TAB_SIZE NR_IRQS #endif |
Code Block |
for (i = 0; i < TAB_SIZE; i++) |
g_mapirq
...
[]
...
An implementation of up_mapirq()
might be something like:
Code Block |
---|
#include <nuttx/irq.h> |
Code Block |
const irq_mapped_t g_irqmap[NR_IRQS] = { ... IRQ to index mapping values ... }; |
Wiki Markup |
g_irqmap
...
[]
...
is
...
a
...
array
...
of
...
mapped
...
irq
...
table
...
indices.
...
It
...
contains
...
the
...
mapped
...
index
...
value
...
and
...
is
...
itself
...
indexed
...
by
...
the
...
physical
...
interrupt
...
vector
...
number.
...
It
...
provides
...
an
...
irq_mapped_t
...
value
...
in
...
the
...
range
...
of
...
0
...
to
...
CONFIG_ARCH_NUSER_INTERRUPTS
...
that
...
is
...
the
...
new,
...
mapped
...
index
...
into
...
the
...
vector
...
table.
...
Unsupported
...
IRQs
...
would
...
simply
...
map
...
to
...
an
...
out
...
of
...
range
...
value
...
like
...
IRQMAPPED_MAX
...
.
...
So,
...
for
...
example,
...
if
...
g_irqmap
...
[37]
...
== 24
, then the hardware interrupt vector 37 will be mapped to the interrupt vector table at index 24. if g_irqmap[42] == IRQMAPPED_MAX
, then hardware interrupt vector 42 is not used and if it occurs will result in an unexpected interrupt crash.
Hardware Vector Remapping
...
...
[This
...
technical
...
approach
...
is
...
discussed
...
here
...
but
...
is
...
discouraged
...
because
...
of
...
technical
...
"Complications"
...
and
...
"Dubious
...
Performance
...
Improvements"
...
discussed
...
at
...
the
...
end
...
of
...
this
...
section.]
...
Most ARMv7-M architectures support two mechanism for handling interrupts:
...
The first time that xyz_vector.h
included, it defines the hardware vector table. The hardware vector table consists of NR_IRQS
32-bit addresses in an array. This is accomplished by setting:
Code Block |
---|
#undef VECTOR #define VECTOR(l,i) .word l |
Code Block |
#undef UNUSED #define UNUSED(i) .word stm32_reserved |
...
These are the valus of UNUSED
and VECTOR
macros on the second time the xzy_vector.h
is included by stm32_vectors.S
:
Code Block |
---|
.macro HANDLER, label, irqno .thumb_func \label: mov r0, #\irqno b exception_common .endm |
Code Block |
#undef VECTOR #define VECTOR(l,i) HANDLER l, i |
Code Block |
#undef UNUSED #define UNUSED(i) |
In the above USART1 example, a single handler would be generated that will provide the IRQ number 12. Remember that 12 is the expansion of the macro STM32_IRQ_USART1
that is provided in the arch/arm/include/stm32/xyz_irq.h
header file:
...
Code Block |
---|
... VECTOR(stm32_usart1, STM32_IRQ_USART1 << 8 | STM32_INDEX_USART1) UNUSED(0) UNUSED(0) ... |
The
...
STM32_INDEX_USART1
...
would
...
have
...
the
...
value
...
12
...
and
...
STM32_IRQ_USART1
...
would
...
be
...
as
...
before
...
(53).
...
This
...
encoded
...
value
...
would
...
be
...
received
...
by
...
irq_dispatch()
...
and
...
it
...
would
...
decode
...
both
...
the
...
index
...
and
...
the
...
physical
...
vector
...
number.
...
It
...
would
...
use
...
the
...
index
...
to
...
look
...
up
...
in
...
the
...
g_irqvector
...
[]
...
table
...
but
...
would
...
pass
...
the
...
physical
...
vector
...
number
...
to
...
the
...
interrupt
...
handler
...
as
...
the
...
IRQ
...
number.
A lookup would still be required in irq_attach()
in order to convert the physical vector number back to an index (100 uint8_t
entries in our example). So some lookup is unavoidable.
...