> What’s New ? <
CMSIS-SVD¶
Arm Cortex-M Microcontrollers¶
In 2021 Arm Cortex-M micro controllers are one of the worlds most popular embedded device families. Eight billion STM32L0xx were manufactured in the last seven years and the STM32L0xx series are only a small part of the STM32xxxx family who are only one licensee/manufacturer of Cortex-M devices.
Cortex-M devices are available in every type and configuration imaginable, some models have ninety three internal peripherals and each one has many registers each with many bitfields.
Some Cortex-M Statistics.
MCU |
Peripherals |
Registers |
Register Bitfields |
Clock Max |
---|---|---|---|---|
STM32F0xx |
37 |
413 |
3044 |
45 |
STM32F303x |
38 |
549 |
3857 |
|
STM32F103xx |
53 |
722 |
4833 |
75 |
STM32F407 |
91 |
1540 |
12347 |
168 |
TM4C129x |
65 |
2137 |
7347 |
120 |
STM32F7x |
89 |
1737 |
14091 |
|
STM32F7x7 |
93 |
2093 |
17051 |
200 |
Embedded Sourcecode¶
The massive versatility of Cortex-M comes at the price of a daunting array of peripherals, registers and bitfields, all of which require configuration if they are to be used.
Regardless of the programming language this means that an automated method is required to provide memory mapped register lists.
Cmsis-svd¶
The CMSIS System View Description format (CMSIS-SVD) formalizes the description of the system contained in Arm Cortex-M processor-based micro controllers, in particular, the memory mapped registers of peripherals. The detail contained in system view descriptions is comparable to the data in device reference manuals. The information ranges from high level functional descriptions of a peripheral all the way down to the definition and purpose of an individual bit field in a memory mapped register.
ARM created SVDConv.exe to generate C Header and Include files from CMSIS-SVD but these are however of no use to Unix embedded Forth users. SVD2FORTH was therefore developed (initially based on work by Ralph Doering https://github.com/ralfdoering/cmsis-svd-fth) to provide Forth Words which do much the same thing.
Are XML text files detailing all peripheral registers for ARM MCU families.
May be downloaded from https://github.com/posborne/cmsis-svd/archive/master.zip (39MB) or found in some of the packages here for which svd files have been specially created.
Keil, now owned by ARM, have SVD PACKS for all the MCU’s which may be downloaded from their site.
Do not contain ARM specific information such as SYSTICK etc.
Svd2forth¶
SVD2FORTH takes a STM32 CMSIS-SVD file as input and transforms it into Forth Words plus an assembly EQU file.
Was created to use CMSIS-SVD files for automated Mecrisp-Stellaris Forth memory-mapped Word production, making target software development much easier and less error prone.
Enforces CMSIS compliant naming across all Mecrisp-Stellaris programs, enabling code reuse.
Creates memory mapped Words, bitfield Words, and a EQUATES file for Assembly use.
Easy to use; enter the name of your SVD in the Makefile and then enter “make everything”.
Developed on FreeBSD but also tested on a Ubuntu 16.04.1 x64 VM. This is for Unix and won’t run on Microsoft Windows unless you install all the stuff that turns Windows into a limited pretend Unix.
What does it look like ?¶
Note
These may differ between different versions.
STM32F407.memmap.fs¶
$50060800 constant RNG ( Random number generator )
RNG $0 + constant RNG_CR ( read-write ) \ control register
RNG $4 + constant RNG_SR ( ) \ status register
RNG $8 + constant RNG_DR ( read-only ) \ data register
STM32F407.bitfields.fs¶
\ RNG_CR (read-write) Reset:0x00000000
: RNG_CR_IE ( -- x addr ) 3 bit RNG_CR ; \ RNG_CR_IE, Interrupt enable
: RNG_CR_RNGEN ( -- x addr ) 2 bit RNG_CR ; \ RNG_CR_RNGEN, Random number generator enable
\ RNG_SR (multiple-access) Reset:0x00000000
: RNG_SR_SEIS? ( -- 1|0 ) 6 bit RNG_SR bit@ ; \ RNG_SR_SEIS, Seed error interrupt status
: RNG_SR_CEIS? ( -- 1|0 ) 5 bit RNG_SR bit@ ; \ RNG_SR_CEIS, Clock error interrupt status
: RNG_SR_SECS? ( -- 1|0 ) 2 bit RNG_SR bit@ ; \ RNG_SR_SECS, Seed error current status
: RNG_SR_CECS? ( -- 1|0 ) 1 bit RNG_SR bit@ ; \ RNG_SR_CECS, Clock error current status
: RNG_SR_DRDY ( -- x addr ) 0 bit RNG_SR ; \ RNG_SR_DRDY, Data ready
\ RNG_DR (read-only) Reset:0x00000000
: RNG_DR_RNDATA? ( -- x ) RNG_DR @ ; \ RNG_DR_RNDATA, Random data
STM32F407.equates.s¶
For use with assembly language
@ Example: enable GPIOB
@ ldr r0, = RCC_AHBENR @ load AHB Peripheral Clock enable register ADDRESS into MCU register r0
@ ldr r1, [r0] @ load existing CONTENTS of AHB Peripheral Clock enable register into r1
@ ldr r2, = RCC_AHBENR_iopben @ load I/O port B clock enable Bitfield into r2
@ orrs r2, r1 @ Orrs with previous contents of AHB Peripheral Clock enable register
@ str r2, [r1] @ save back to AHB Peripheral Clock enable register, any previous set bits are unchanged
@ Example: Set GPIOB-8 to INPUT, GPIOB-7 to OUTPUT (requires gpio-equates.s)
@ ldr r0, = GPIOB_MODER @ GPIOB port mode register
@ ldr r1, [r0]
@ ldr r2, = (INPUT << GPIOB_MODER_MODER8) + (OUTPUT << GPIOB_MODER_MODER7)
@ orrs r2, r1
@ str r2, [r0]
@=========================== RNG ===========================@
.equ RNG_BASE, 0x50060800 @ Random number generator
.equ RNG_CR, RNG_BASE + 0x0 @ ([read-write] reset = 0x00000000) control register
.equ RNG_CR_IE, 1 << 3 @ Interrupt enable
.equ RNG_CR_RNGEN, 1 << 2 @ Random number generator enable
.equ RNG_SR, RNG_BASE + 0x4 @ ([] reset = 0x00000000) status register
.equ RNG_SR_SEIS, 1 << 6 @ Seed error interrupt status
.equ RNG_SR_CEIS, 1 << 5 @ Clock error interrupt status
.equ RNG_SR_SECS, 1 << 2 @ Seed error current status
.equ RNG_SR_CECS, 1 << 1 @ Clock error current status
.equ RNG_SR_DRDY, 1 << 0 @ Data ready
.equ RNG_DR, RNG_BASE + 0x8 @ ([read-only] reset = 0x00000000) data register
.equ RNG_DR_rndata, 0 @ Width:32, Random data
Register Pretty Printing¶
Assume you want to find if the HSI clock is enabled and running, and if the PLL is on ? You know these bitfields are in the RCC_CR register and so you look up the Reference Manual and find the bitfield format as below.
Now you want to find out those values RIGHT NOW. Forth is perfect for this, you can just use the interactive terminal to find out. We know that the memory map has already been loaded so the data IN the RCC_CR register can easily be found.
RCC_CR @ hex. 00005183 ok
Hmm, it’s not immediately obvious what the states of the bitfields we want are. Lets turn it to binary ?
binary $5183 . 101000110000011 ok.
Better, but I don’t like counting bits on the screen, too easy to make a mistake.
Fortunately SVD2FORTH has a better way, just type the following in the terminal:
RCC_CR.
Now it is obvious that HSI is ON and READY, and that the PLL is not. If we know the bitfields by heart already we don’t even need the Technical Manual.
This also makes group problem solving over chat groups, IRC etc, very easy because no one needs to waste their time looking up manuals, and decoding your hex or binary number. If you want expert free help, it’s incumbent on you to waste as little of their time as possible.
Note
This is a SVD2FORTH for the STM32F051 with custom legends. The generic SVD2FORTH packages will not have custom legends, just the bit position labels.
Namespace Collisions¶
Firstly, what is a “namespace” ?
In computing, a namespace is a set of signs that are used to identify and refer to objects of various kinds. A namespace ensures that all of a given set of objects have unique names so that they can be easily identified. Namespaces are commonly structured as hierarchies to allow reuse of names in different contexts.
Namespaces are used in Mecrisp-Stellaris Forth to access all the on chip peripherals.
This naming usually takes the form of “peripheral/register” in a memory map file of Forth Words.
As described above, SVD2FORTH will create all these register memory maps automatically from the CMSIS-SVD.
However these are still often hand transcribed from a Technical Manual leading to Namespace Collisions, let me explain.
Namespace Example1¶
This example is from RP2040 user source which appears to be hand transcribed from the Technical Manual.
$d0000000 constant SIO_BASE \ SIO registers
SIO_BASE $000 + constant CPUID \ Processor core identifer
Note
The correct CMSIS-SVD name for “CPUID” (in this instance) is actually “SIO_CPUID”, however the “peripheral” part has been omitted by the author.
Namespace Example2¶
These are taken from a RP2040 memory map auto generated by SVD2FORTH https://sourceforge.net/projects/mecrisp-stellaris-folkdoc/files/RP2040.memmap.fs
$D0000000 constant SIO_CPUID \ Processor core identifier Value is 0 when read from processor core 0, and 1 when read from processor core 1.
$E000ED00 constant PPB_CPUID \ Read the CPU ID Base Register to determine: the ID number of the processor core
Warning
As can be seen above, within RP2040.memmap.fs, the name “CPUID” is NOT unique.
The Collision Problem¶
This is what would happen if both these register names lacking the “peripheral” part (as in Namespace Example1) were uploaded.
$D0000000 constant CPUID ok.
...
...
...
$E000ED00 constant CPUID Redefine CPUID. ok.
The namespace collision would cause a ‘Redefine’ warning, and the last one loaded would replace the previous one(s).
In case you’re wondering, if you remove the “peripheral” component from the names listed in RP2040.memmap.fs there will be 178 collisions. Here are the first ten, sorted by number of copies.
Identical Names, Different Addresses¶
10 INTR
7 CTRL
6 INTS
6 INTF
6 INTE
3 CS
2 WDSEL
2 VOLTAGE_SELECT
2 UARTRSR
2 UARTRIS
Solution¶
Simply put, don’t write the peripheral constants manually, use the full auto transformed namespaces from the official mcu CMSIS-SVD file. This will stop namespace collisions, reduce debugging and make your source reusable for others using the same namespaces.
This advice also applies for Assembly Language programs.
Svd2forth Download LATEST V3 Generic Release¶
Note
Svd2forth is for ST Micro MCU SVD’s, other makes may not be transformed properly.