TI/Hercules RM57
The RM57 is part of TI’s Hercules family of ARM Cortex-R5F safety microcontrollers, aimed at applications that need lockstep execution and built-in self-test (industrial, medical, and automotive safety systems). NuttX currently supports the RM57L843 part.
Warning
Support for this chip family is new and has been tested on a single LAUNCHXL2-RM57L (RM57L843 Rev B). The table below says how far each peripheral was tested. Where it says loopback only, the peripheral’s internal loopback mode was used: the driver logic is tested, but nothing at the pins (signal timing, a real device, a real bus) has been checked.
Peripheral Support
The following list indicates RM57 peripherals currently supported in NuttX:
Peripheral |
Notes |
|---|---|
Core |
Lockstep-safe start-up, PLL (300MHz GCLK, 150MHz HCLK,
75MHz VCLK), SRAM ECC, MPU, VIM interrupt controller and
RTI system tick. Tested on hardware with |
ESM |
Error Signalling Module. With
|
Self test |
Optional start-up diagnostics ( |
SCI |
SCI1-SCI4. SCI1/LIN1 and SCI2/LIN2 are dual-role SCI/LIN modules; the serial driver always runs them in SCI compatibility mode (GCR1 LIN_MODE=0). Interrupt-driven by default; optional RX/TX DMA (see Serial DMA below). Used for the console. Tested on hardware: console with and without DMA, SCI3 in internal loopback with DMA. |
LIN |
Configuration and polled-transfer scaffold only
( |
DMA |
32-channel, 48-request-line DMA controller
( |
DCAN |
All four DCAN (Bosch D_CAN, CAN 2.0A/B) controllers
( |
GIO |
General purpose I/O with pin interrupts
( |
MibSPI |
SPI master on all five MibSPI modules
( |
I2C |
I2C1 and I2C2 master ( |
ADC |
Both MibADC modules ( |
EMAC |
10/100 Ethernet MAC + EMAC Control module + MDIO
( |
Todo
Not implemented yet: N2HET, ePWM, eCAP, eQEP, EMIF, the CRC module, the RTI digital watchdog and flash programming. Contributions are welcome.
Safety diagnostics
CONFIG_RM57_SELFTEST runs the start-up diagnostics before the OS
starts: an ESM group 3 check, the PBIST ROM tests (with the errata
PBIST#4 workaround), the STC self-check and CPU logic BIST, the four
CCM-R5F diagnostics in all three modes, the eFuse controller tests
(power-on reset only), and the L2RAMW ECC and address decode tests. The
result of each test is printed on the console. A failing test drives
nERROR, and with CONFIG_RM57_SELFTEST_HALT_ON_FAIL stops the boot.
The CCM-R5F is off while a debugger is attached, so the ROM tests, the
STC and the CCM diagnostics report skipped in a debug session. The
CONFIG_RM57_SELFTEST_INJECT_* options inject one fault per build to
check that the detection path works. All five injected faults were
detected on the board. The selftest board configuration shows the
console output.
At run time, VIM channel 0 (the ESM high-level interrupt) is hard-wired
to FIQ. With CONFIG_ARMV7R_DECODEFIQ the ESM handler decodes,
reports and clears each pending channel. Without that option the FIQ
vector does nothing, and a latched nonmaskable group 2 error is never
acknowledged.
MibSPI
All five MibSPI modules work as SPI masters through the standard
spi_dev_s interface. Each module can be set up in one of three ways:
compatibility mode with polled transfers (default);
compatibility mode with DMA (
CONFIG_RM57_MIBSPIn_DMA);multi-buffer mode using transfer group 0 (
CONFIG_RM57_MIBSPIn_MULTIBUF).
Chip selects are driven as GIO. On this board only MibSPI1 and MibSPI3
are routed to headers, and they are registered as /dev/spi1 and
/dev/spi3.
CONFIG_RM57_MIBSPI_LOOPBACK adds a start-up test. It uses
SPIGCR1.LOOPBACK and sends patterns of 1 to 1000 words, 8 and 16 bits
wide, at 1MHz and 37.5MHz, then reads them back. Every mode passes this
test on both modules. Internal loopback cannot show the clock polarity
and phase at the pins, so the CPOL/CPHA mapping and the real SPICLK rate
are not measured yet.
I2C
I2C1 and I2C2 work as interrupt-driven masters through i2c_master_s
(standard and fast mode, repeated START, I2C_M_NOSTART,
CONFIG_I2C_RESET). Slave mode and DMA are not supported. The
LAUNCHXL2-RM57L has no I2C pull-up resistors, so a real bus needs
external ones (2.2k to 4.7k).
CONFIG_RM57_I2C_LOOPBACK adds a start-up test that uses digital
loopback (MDR.DLB) on each bus at 100kHz and 400kHz. On the board,
all tests pass, and a timed 2048-byte write takes 101% of the nominal
time. Digital loopback only works for master transmit, so master
receive, real ACK/NACK handling and the SCL timing at the pin are not
measured yet.
DCAN
Each of the four DCAN controllers has 64 ECC-protected message objects.
The driver partitions them into a transmit FIFO at the top of the range
(CONFIG_RM57_DCAN_TXFIFO_DEPTH, default 8) and receive filter FIFOs
below it (CONFIG_RM57_DCAN_RXFIFO_DEPTH objects per acceptance
filter, up to CONFIG_RM57_DCAN_NFILTERS_MAX filters, with an
accept-everything filter installed while no user filter is active).
Message-object interrupts for reception are routed to the DCAN’s level 1
interrupt line, transmission and status/error to level 0.
Per instance, RM57_DCANn_CHARDRIVER selects the classic character
driver (bit timing, acceptance filter, loopback/silent mode, bus-off
recovery, NART and ABOM ioctls; error reporting with
CONFIG_CAN_ERRORS) and RM57_DCANn_SOCKET selects SocketCAN
(candump/cansend work out of the box; error frames with
CONFIG_NET_CAN_ERRORS, bit timing via SIOCGCANBITRATE /
SIOCSCANBITRATE).
Three receive paths are available per instance:
RM57_DCANn_RX_PIO(default): interrupt per message, read through interface register set 2.RM57_DCANn_RX_IF3IRQ: the message handler auto-copies received objects into interface register set 3; the dedicated IF3 interrupt reads them without any interface-register busy-wait.RM57_DCANn_RX_IF3DMA(CONFIG_EXPERIMENTAL): as above, but a DMA channel in auto-initiation mode moves the IF3 image to memory; a watchdog guards against lost request pulses.
The CAN clock (VCLKA1) is mapped to VCLK (75 MHz with the default board
clocking); the bit-timing search targets a 75% sample point, matching
TI’s HALCoGen defaults (500 kbit/s -> BRP=10, TSEG1=10, TSEG2=4).
DCAN1-DCAN3 use dedicated balls (A10/B10, H2/H1, M18/M19); DCAN4 is
pin-multiplexed with GIOB[2] and GIOB[3] (F2/W10) and the board claims
those balls when RM57_DCAN4 is enabled. The LAUNCHXL2-RM57L has no
CAN transceiver on board - every DCAN ball runs to a BoosterPack header
at CMOS levels, so a real bus needs an external transceiver, while the
loopback test mode still drives the TX ball for logic-analyzer capture.
The board configurations can (character driver,
loopback self-test), cansock (SocketCAN with candump/cansend) and
candma (IF3 DMA receive path) are provided. In loopback on the board,
can -n 8 receives all 8 frames, and the bit timing the driver
computes is the same as HALCoGen’s. A real bus (ACK from another node,
arbitration, bus-off recovery) has not been tested.
Serial DMA
Each SCI port can optionally use the DMA controller for RX and/or TX,
independently, via CONFIG_RM57_SCIn_RXDMA / CONFIG_RM57_SCIn_TXDMA
(n = 1-4; both require CONFIG_RM57_DMA). Because SCI1/LIN1 and
SCI2/LIN2 are run in SCI-compatibility mode (single-buffer, MBUF_MODE=0),
the SCI module generates one DMA request per byte in each direction (TRM
SPNU562A section 28.2.3) - there is no multi-byte burst transfer for a
single UART frame.
RX DMA writes into a per-port circular ring buffer sized by
CONFIG_RM57_SERIAL_RXDMA_BUFFER_SIZE (rounded up to a multiple of the
Cortex-R5’s 32-byte D-cache line size). New bytes are picked up when the
DMA half/full (“HBC”/”BTC”) interrupt fires, which alone would leave
short, infrequent messages sitting in the ring buffer until it is half
full. Unlike, say, the STM32 USART, the SCI has no idle-line interrupt
to signal the end of a shorter burst, so rm57_serial_dma_poll()
flushes the rings instead.
CONFIG_RM57_SERIAL_RXDMA_POLL (enabled by default whenever a port
uses RX DMA) dedicates RTI compare 1 to calling it at
CONFIG_RM57_SERIAL_RXDMA_POLL_HZ (1 kHz by default), which bounds
the added receive latency by one poll period and is what makes an RX
DMA console usable interactively. Compare 1 shares free-running counter
0 with the system tick on compare 0, so no additional timer hardware is
consumed. Disable the option if every RX DMA port is used purely for
bulk transfers and the interrupt is not wanted.
The underlying hardware DMA request lines used are fixed per SCI instance (datasheet SPNS215C Table 6-41):
SCI instance |
RX request |
TX request |
|---|---|---|
SCI1/LIN1 |
28 |
29 |
SCI3 |
30 |
31 |
SCI2/LIN2 |
40 |
41 |
SCI4 |
42 |
43 |
ADC (MibADC)
The RM57L843 has two MibADC modules. ADC1 serves 32 analog inputs and ADC2
serves 25, of which 16 are the same balls ADC1 sees. Both are successive
approximation converters that run at either 10- or 12-bit resolution, and
both are enabled independently with CONFIG_RM57_ADC1 and
CONFIG_RM57_ADC2.
Conversion groups
Each module contains three independent conversion groups - the Event group,
Group1 and Group2. A group owns its channel selection mask, trigger source,
sampling window, slice of the results memory and VIM interrupt channel, so
the driver registers each enabled group as a separate character device.
Devices are numbered /dev/adc0 upwards in the order the groups are
enabled, ADC1 before ADC2 and Event before Group1 before Group2.
A group is enabled with CONFIG_RM57_ADCn_EV, ..._G1 or ..._G2,
and configured with the options underneath it: ..._CHANMASK selects the
channels, ..._ACQ the sampling window, ..._BUFS its share of the
results memory, ..._THRESHOLD how many results accumulate before the
group interrupts, and ..._CONTINUOUS whether the channels are converted
once per trigger or continuously.
Results memory
Each module has a 64-word results RAM that its three groups divide between
them. The hardware allocates it in pairs of buffers through a single
register, so the split is computed for the whole module from every group’s
..._BUFS value. The Event group and Group1 counts must therefore be even,
and a module’s three groups must not ask for more than 64 words in total;
both rules are checked at compile time.
The RAM is auto-initialized to zero at start-up through the system module’s
memory initialization controller, which is what makes it safe to switch on
the parity checking enabled by default with CONFIG_RM57_ADC_PARITY. A
parity error is reported to the Error Signalling Module.
Conversion clock
ADCLK is VCLK divided by a prescaler. Rather than expose the divider,
CONFIG_RM57_ADCn_CLOCK names the wanted frequency and the driver derives
the prescaler from BOARD_VCLK_FREQUENCY, rounding so the result never
exceeds the request. SPNS215 specifies a tc(ADCLK) of at least 33ns, an
ADCLK ceiling of 30MHz, which is asserted at compile time. The default of
9.375MHz is VCLK/8 on a board running VCLK at 75MHz.
Triggering
Group1 and Group2 are software triggered by default: writing the channel
selection starts a conversion. Setting CONFIG_RM57_ADCn_Gx_HWTRIG makes
them wait for one of eight hardware sources instead, selected with
..._TRIGSRC - the ADxEVT pin, four N2HET1 outputs, an RTI compare match
or two GIOB pins. The Event group has no such choice: it is always started
by its trigger source, so only the source and its edge are configurable.
When the ADxEVT pin is not used as a trigger it can serve as a general
purpose I/O through the ANIOC_RM57_EVTPIN ioctl. AD1EVT is on ball N19,
which can also carry MII_RX_ER. The LAUNCHXL2-RM57L takes MII_RX_ER from its
dedicated ball U5 instead, so AD1EVT is still available when
CONFIG_RM57_EMAC is enabled.
Result transfer
By default a group’s interrupt handler drains the results FIFO and hands
each sample to the upper half. Selecting CONFIG_RM57_ADC1_Gx_DMA moves
them with the DMA controller instead, into a two-half ring that lets the ADC
fill one half while the other is delivered as a batch. ADC1 has dedicated
DMA request lines; ADC2’s are alternate functions shared with MibSPI1 and
MibSPI3 and would need the system module’s request source mux reprogrammed,
so ADC2 has no DMA option.
Calibration and diagnostics
With CONFIG_RM57_ADC_CALIBRATE (the default) the driver runs the offset
error calibration when a module’s first group is registered: four internal
reference voltages are converted, and the deviation of their average from
mid scale is loaded into the correction register that the hardware adds to
every subsequent result. ANIOC_RM57_CALIBRATE repeats it on demand and
ANIOC_RM57_MIDPOINTCAL runs the differential variant, which cancels the
mismatch of the internal bridge resistors.
ANIOC_RM57_SELFTEST drives each reference onto one input through an
internal test resistor and classifies the channel as healthy, open, or
shorted to ground or supply.
CONFIG_RM57_ADC_MAGCOMP builds support for the three hardware magnitude
comparators of each module, which interrupt when a monitored channel crosses
a threshold - either a fixed value or the latest result of a second channel.
The generic ANIOC_WDOG_UPPER and ANIOC_WDOG_LOWER commands are backed
by the first two of them.
Channel order
Channels are normally converted in ascending channel number. ADC1 also
supports a look-up table based order, built with
CONFIG_RM57_ADC_ENHANCED_CHSEL and loaded through
ANIOC_RM57_SET_CHNSEQ, which converts an arbitrary user-defined sequence
and can drive an external analog multiplexer alongside it. ADC2 does not
implement this mode.
On-chip temperature sensors
The device carries three on-die temperature sensors, each multiplexed onto one
ADC channel: sensor 1 on ADC1 channel 31, sensors 2 and 3 on ADC2 channels 31
and 30. They are enabled with CONFIG_RM57_ADC_TEMPSENSOR and selected
individually with CONFIG_RM57_ADC_TEMP1 to ..._TEMP3.
Out of reset all three are powered down and their channels are wired to the
external balls instead, so the driver has to release them and re-mux them
through the IOMM. Sensor 1 shares its channel with the AD1IN[31] ball
(T13), which means enabling it gives up that ball as an analog input; sensors
2 and 3 sit on channels that have no ball at all, so they cost nothing.
Readings are calibrated. During device test TI records three (ADC reading, temperature) points per sensor in OTP, and the driver reads them back and interpolates, so results come out in real degrees Celsius rather than raw codes. The calibration was taken with ADREFHI at 3.3V, which is what this board supplies, so no scaling correction is applied. If OTP holds no usable calibration the driver reports the raw reading and refuses to invent a temperature.
By default each enabled sensor is registered as a character device,
CONFIG_RM57_ADC_TEMP_PATH with the device number appended - /dev/temp0
and upwards, numbered from CONFIG_RM57_ADC_TEMP_DEVNO. One read()
returns a whole struct rm57_adc_temp_s:
struct rm57_adc_temp_s temp;
int fd = open("/dev/temp0", O_RDONLY);
read(fd, &temp, sizeof(temp));
if (temp.calibrated)
{
printf("%d.%03d C\n", temp.millicel / 1000, abs(temp.millicel % 1000));
}
Every read runs a fresh conversion and none of them reports end of file, so
read a fixed length rather than pointing cat at the node.
CONFIG_RM57_ADC_TEMP_UORB swaps that for the sensor framework, registering
each sensor as /dev/uorb/sensor_tempN instead:
nsh> sensortest -n 5 temp0
That is the friendlier interface - poll() and the sensortest
application come with it - but it selects CONFIG_SENSORS and pulls in the
whole UORB upper half, which is a lot to carry for a die temperature. It also
costs the calibration flag, since struct sensor_temp has nowhere to put
it: an uncalibrated sensor fails the read with ENODATA rather than handing
back a qualified reading.
Blocking reads are not among what it buys, though. These sensors are
fetch-mode, and the upper half serves a blocking reader by parking it on a
per-subscriber semaphore that only a pushing driver ever posts - so a
fetch-mode node must be opened O_NONBLOCK, which is what sensortest
does and what sensor_poll() is written to accommodate. Pointing cat at
one of these nodes hangs.
The type is SENSOR_TYPE_TEMPERATURE rather than
SENSOR_TYPE_AMBIENT_TEMPERATURE: these sensors measure the junction, not
the room. Readings are fetched on demand - a conversion runs when someone
reads - so there is no sampling period to configure and SNIOC_SET_INTERVAL
is accepted and ignored.
Under either arrangement the sensors are also reachable through the
ANIOC_RM57_GET_TEMP ioctl on any /dev/adcN, which fills in the same
struct rm57_adc_temp_s.
A temperature reading borrows one conversion group for the duration of a single conversion, saving and restoring its channel selection, mode and interrupt enables. A group that is converting continuously therefore loses a few microseconds of sampling to each temperature read.
EMAC/MDIO (Ethernet)
The RM57L843 has a single 10/100 Ethernet MAC built from three sub-blocks
(SPNU562A chapter 31): the EMAC module itself (TX/RX CPPI DMA engines,
statistics, MAC address/hash filtering), the EMAC Control module (VIM
interrupt pacing/routing), and the MDIO module (a shared PHY management
bus, independent of the MAC). CONFIG_RM57_EMAC enables all three
together and registers one netdev_register() interface
(NET_LL_ETHERNET) - there is no separate character-device frontend,
unlike DCAN.
Descriptor rings (TX: CONFIG_RM57_EMAC_NTXDESC, default 8; RX:
CONFIG_RM57_EMAC_NRXDESC, default 16) live in the EMAC’s internal 8KB
CPPI RAM, which this port’s MPU maps as non-cacheable device memory, so
descriptor fields need no cache maintenance. Packet buffers are ordinary
cacheable SRAM; TX uses a small zero-copy free-buffer pool (buffers are
swapped into dev->d_buf, not copied) while RX buffers are fixed 1:1
with RX descriptors and processed synchronously in place. Both rings are
managed as CPPI “append to a running queue” chains (SPNU562A Section
31.2.6.2), including the documented EOQ-race recovery for restarting a
channel that halted between the driver reading its tail and appending a
new descriptor.
CONFIG_RM57_EMAC_MII / CONFIG_RM57_EMAC_RMII select the PHY
interface mode. The IOMM reset default is RMII, but the LAUNCHXL2-RM57L’s
DP83630 PHY is strapped for MII with no way to change it, so that board
must select MII. The EMAC’s internal logic clock (VCLKA4_DIVR_EMAC)
must be exactly 25MHz for MII or 50MHz for RMII (SPNS215 Section 6.6.3);
see the BOARD_VCLKA4_* comment in the board’s board.h. Only MII
has been tested on hardware. The RMII path (clocked from PLL2) builds,
but no board available to this port wires RMII.
The MDIO module addresses up to 32 PHYs (CONFIG_RM57_EMAC_PHYADDR,
default 1) over a single-transaction register interface
(USERACCESS0), and generates a link-change interrupt
(LINKINT0, routed through the C0_MISC_PULSE VIM channel) that
this driver always keeps enabled for its own netdev_carrier_on/off
tracking; CONFIG_RM57_EMAC_PHY_INTERRUPT additionally exposes that
event to userspace via SIOCMIINOTIFY/phy_notify.
CONFIG_RM57_EMAC_AUTONEG (default) negotiates speed/duplex; disabling
it forces the mode selected by CONFIG_RM57_EMAC_ETHFD /
CONFIG_RM57_EMAC_ETH100MBPS. CONFIG_RM57_EMAC_LOOPBACK sets
MACCONTROL.LOOPBACK and skips the PHY link wait entirely, so the
descriptor ring and interrupt path can be exercised standalone without a
PHY or cable - the Ethernet equivalent of RM57_DCAN_LOOPBACK.
Multicast group membership (CONFIG_NET_MCASTGROUP) is implemented via
the EMAC’s 64-bit hash address table (SPNU562A Section 31.5.37, 6-bit
XOR-fold of the destination address), with a per-bit reference count
since two joined addresses can hash to the same bit.
The four EMAC Control module interrupt pulses this device routes to the
VIM (SPNS215 Table 6-39) are, in channel order: C0_MISC_PULSE (76,
statistics/host-error/MDIO events), C0_TX_PULSE (77, TX completion),
C0_THRESH_PULSE (78, RX flow-control threshold - not used by this
driver), C0_RX_PULSE (79, RX completion). Each ISR follows the
disable-service-acknowledge-reenable discipline SPNU562A Section
31.2.17.3 documents: the top-half clears the relevant EMAC Control
enable bit and defers to the low-priority work queue, which does the
real work, writes the MACEOIVECTOR acknowledge key, then re-enables
the source last.
The eth board configuration (CONFIG_NETDEV_LATEINIT) derives a
locally-administered MAC address from the device’s unique die ID at
board bring-up; without CONFIG_NETDEV_LATEINIT the interface
self-registers via arm_netinitialize() with a fixed placeholder
address (02:00:00:00:00:01) instead.
Tested on the LAUNCHXL2-RM57L at 100Mbit/s full duplex: DHCP, ping (RTT
2-7ms through a home router), DNS, NSH over telnet and HTTP all work.
With iperf the best measured TCP throughput is 19.4Mbit/s for
transmit (board as client) and 9.2Mbit/s for receive (board as server).
After a 10MB transfer, every EMAC error counter reads zero. On some boots
the DHCP server does not answer the first DISCOVERs, so the eth
configuration raises CONFIG_NETUTILS_DHCPC_RETRIES to 10.