Why are periperal registers 16 bit only on 32 bit MCUs such as STM32 and GD32VF103?

771 views Asked by At

On 32 bit microcontrollers such as the ST STM32F103 (ARM core) or the GigaDevices GD32VF103 (RISC-V core) there are many registers for dealing with peripherals.

What surprises me is that peripheral registers that require more than 16 bits are split into 2 registers, i.e. a high and low register - although the word size (and thus standard register size) of the CPU is 32 bits! Example: RTC_CNTH and RTC_CNTL (for reading the current RTC counter value).

Thus, code for reading/writing them gets tedious and errorprone and there is the issue of non-atomic access. Example:

static uint32_t get_rtc_counter()
{
    uint32_t r = RTC_CNTL;
    r |= RTC_CNTH << 16;
    return r;
}

The GlobalDevices user manual even marks the upper 16 its of these registers as reserved ('must be kept at reset value') - so they are even accessible as 32 bit registers!

Since two vendors are doing this with different MCUs I'm interested in the reasoning behind that.

There must be some technical advantages in using 16 bit registers like this when interacting with peripherals, even if the CPU itself is 32 bit.

Reasons I can think of:

  • when ST started with the STM32 it just reused the peripherals blocks/design from a previous non-32 bit MCU family, such as the ST8 or ST10
  • GlobalDevices copied some STM32F for their ARM MCU family and just re-used their peripherals blocks in their GD32VF103 RISC-V family

But perhaps there are better/real technical reasons behind that.

Perhaps there are other 32 bit MCUs available which don't do this.


Update (2022-05-10): FWIW, the SiFive E310 32 bit RISC-V MCU does things differently! That means it generally uses the whole 32 bits of memory mapped peripheral registers and doesn't split fields into 16 bit halves. For example, its RTC counter is 48 bit wide and is thus split into lower 32 bit and higher 16 bit parts.

2

There are 2 answers

1
hcheung On

To answer the question, it needs to know a little bit of seconductor development history and the design principle of ARM RISC architecuture.

Historically, ARM processors provide a 32-bit instructions set. However, a 32-bit instruction set has a cost in terms of memory footprint of the firmware. This means that a program written with a 32-bit Instruction Set Architecture (ISA) requires a higher amount of bytes of flash storage, and often flash memory are power hungry, especially with the older 14nm node that used by the MCUs like STM32Fx series (as compare to newer 7nm STM32Lx and STM32Gx series). 32-bit ISA has impacts on power consumption and overall costs of the MCUs.

To address such issues, ARM introduced the Thumb 16-bit instruction set, which is a subset of the most commonly used 32-bit one. Thumb instructions are each 16 bits long, and are automatically “translated” to the corresponding 32-bit ARM instruction. This means that 16-bit Thumb instructions are transparently expanded (from the developer point of view) to full 32-bit ARM instructions in real time, without performance loss.

ARM introduced the Thumb-2 instruction set afterward (in 2003?), which is a mix of 16 and 32-bit instruction sets in one operation state. Thumb-2 is a variable length instruction set, and offers a lot more instructions compared to the Thumb one, achieving similar code density.

Cortex-M3/4/7 supports the full Thumb and Thumb-2 instruction sets.

0
old_timer On

When you sit down to write a program do you always/instantly pick one language even if maybe it might not make sense. Need to calculations with imaginary numbers and Fortran is not your instant first choice? When you choose loop variables that count to 10 do you choose or assume that an 8 bit is better? (if so why???). Do you use i,j,k as loop variables or have your own habit?

First off GD clones devices in a somewhat shady way, and their risc-v that I tried, at least, is obviously a cortex-m based device that they swapped out the purchased IP from ARM with some other purchased IP risc-v core.

Yes, in some cases you see vendors with decades of history that take peripherals from a former 8 or 16 bit (for lack of a better term) core and re-using those. Well tested, well used, well understood, fully paid for, why spend tens of thousands of dollars creating another uart with the same features when we already have two or three (of course you can ask ST that question because they have two or three of many of these things).

How and why a chip designer chooses the number of registers, how the fields are distributed through the registers, the width of the registers, the address space and decoding for those registers, etc. For example it might only have 8 bits or 16 bits in the register but is on a 4 byte boundary and can be accessed using a 32 bit transaction.

There is no answer here, you can see if you can contact the engineers directly and have a zoom meeting or something and see if they will let you pick their brains. (good chance they have moved on)(they might have been contractors to start with, very common in the chip business to have most of the work done by contractors during a development phase then they go on to some other company/design having a development phase) Most likely the choice was a matter of seconds based on experience and most of the time not something that they sat down as a team for months and decided on.

With experience you, personally, will hopefully get to work against fpga engineers or asic engineers and see this first hand, but you already know this answer because when you write software you do not sit down with a team for weeks or months to choose the name and size of your variables. Only of you do something so painful to others that someone brings it up in a peer review will that conversation happen, otherwise, your function names, parameters, order of parameters, variable names, etc. Are largely your choice. Hardware is no more magic that software and it is done today using "programming" languages that very much resemble software programming languages. Just like your software they are banging out hundreds/thousands of lines of HDL...

Also, the chip vendor clearly buys IP, some percentage of every chip is purchased IP and some is in house, even with Intel and other big names. Your x86 has a lot of purchased IP in it that intel did not create/invent/own.

And purchased IP, for the same reasons as already stated, will have some form of interface, sometimes they offer a register based interface and a discrete signal based interface, or they offer only one or the other. Once you have been involved in say a purchased ip dram controller or pcie controller or something like that and then go look at your competitors register spec for their controller (or more likely look at their Linux driver as often you cannot include certain portions of the purchased IP information in documentation due to NDA agreements) you can sometimes figure out, ahh, they bought the same controller we did, and use the same init routines...(for certain technology there is a very short list of available IP that everyone uses big name or small).

So it may be that the specific peripheral you are asking about either was purchased and had a 16 bit interface or as you suggest may have been an STM8 or ST7 or other IP from a former product line already owned by ST. And based on the interface it may have been easier for the designer to just make it two separate register accesses than try to turn one 32 bit into two separate on the peripheral. Or left it as two as well as having one in case there was some code internal or external that was already written to access that field in two smaller transactions. You should/will know this as well, you create a library, a co-worker uses it, you change it and cause pain to the co-worker. Well I thought it would be better this way, yeah, but I have thousands of lines of code I have to go touch, peer review, validate, etc. And you get to choose whether you make an enemy of a co-worker that you will need to rely on some day, vs the customer you never see or interact with whose life you think you might be making better.

With respect to what do others do. Since each family or product for each chip vendor is its own development project with real humans that make personal choices based on experience and other factors. You will find products that do this and products that do not. You will find within a company or even with a single chip, where one peripheral does things one way and one peripheral another way. This is all very expected and normal. There are some arm based MCUs that use 8 bit register with only 8 bit transactions to control a peripheral, they have more address space than they can consume, why not make all of the accesses 32 bit? Granted, unlike memory, smaller accesses (8 or 16 bit) to peripherals do not necessarily carry a performance penalty. Just means we the programmer have to, at times, make sure we generate the right instruction.

The other bits reserved is language for 1) we may have a bug and if you change a bit from the reset value the peripheral won't work 2) we might take this peripheral and add features and put it in the next generation chip but if you use the same code with zeros there, it should work in the legacy way 3) we have bits we chose not to document etc. Chip by chip, register by register, you will figure out how much you have to care. Arguably I would personally not assume my code would port even if it looks like the same peripheral on the next chip, I would test it at least, and then understand it might not be exact there may be a zero that needs to be somewhere or I might have to do a read-modify-write. Very often you should do read-modify-writes anyway, not some pointer and equal then a separate or equal mind you but a read...modify...write. And by doing that as a habit (yes there are many exceptions to this, gpio in particular is a lot of read-modify-write, a uart is usually direct writes) you will be preserving these bits marked as reserved (must be zero or do not modify).

Bottom line, if someone actually knows the real answer for those registers, it would likely be a violation of their employment contract or an NDA to provide much information here unless the company has chosen to share that information publicly...then that info would already be out there. Most "why" questions with respect to design are unanswerable though...