Peripherals

Open
#155 6 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
30/100
Issue type
Documentation
Clarity
Mostly clear
Activity status
Stale
Tech stack
rust

Research direction

Start with the chapter at peripherals/index.html and review its sections on peripherals, memory address space, and Linear and Real Memory Space. Compare the current explanations with the proposed terminology, structure, and memory-mapped I/O discussion, including the svd2rust reference. Done means the chapter has a consistent scope and clearer explanations matching the accepted direction.

Written by the indexing model from the issue text.

Description

https://rust-embedded.github.io/book/peripherals/index.html

they contain sections of silicon which are used for interacting with systems outside of the microcontroller

These components are collectively known as Peripherals.

This is not usually how the word "peripheral" is used. For example take the microcontroller from the STM32F3DISCOVERY board. https://www.st.com/en/microcontrollers/stm32f303vc.html

When you search for peripheral you will find sentences in the context of APB and I2S buses.

But under the definition of the book, the following items would also be peripherals:

  • GPIO
  • DMA controller
  • ADC
  • analog comparator
  • OpAmps
  • USB

And the following would be left undiscussed:

  • CRC calculation unit
  • DSP functions
  • crypto functions
  • power management
  • clock management
  • timers
  • RTC (integrated)

Peripheral is usually used for nearby chips that interface with the microcontroller. Although the definition can extend to more things this is not usually how it's described on product pages.

These peripherals are useful because they allow a developer to offload processing to them, avoiding having to handle everything in software.

This is wrong wording "offload". It's not as if an ADC for example can be run in software.
Maybe when talking about "offloading" it is again in the sense that there are co-processor-like IC's on the same board.

One could argue that the input of an ADC can not come from "a system", but could it?

Suggestion:
Rename the chapter from peripherals to "on-chip hardware". Then split this section into hardware that interfaces through the pins of the microcontroller and hardware that can not use a pin.

If you look at the main circuit board in an old-fashioned home computer from the 1970s or 1980s (and actually, the desktop PCs of yesterday are not so far removed from the embedded systems of today) you would expect to see:

    A processor
    A RAM chip
    A ROM chip
    An I/O controller

The RAM chip, ROM chip and I/O controller (the peripheral in this system) would be joined to the processor through a series of parallel traces known as a 'bus'. This bus carries address information, which selects which device on the bus the processor wishes to communicate with, and a data bus which carries the actual data. In our embedded microcontrollers, the same principles apply - it's just that everything is packed on to a single piece of silicon.

I would remove the computer history from this chapter. The point is that some things are always a necessity for a CPU (even since the old days). The chapter should start with these essential things as a small introduction and then later dive into the "on-chip hardware" explanation.

peripherals are exposed to our Microcontroller with a hardware interface, which is mapped to a chunk of the memory.

This can not be understood by itself. It's missing an introductory sentence to the next paragraph. Add: "which will be explained in the following section"

On a microcontroller, writing some data to some other arbitrary address, such as 0x4000_0000 or 0x0000_0000, may also be a completely valid action.

also ? no other valid action was covered before.


Memory address space

This is not explained well enough. What should be explained here is that the memory address space is split into a section for the RAM and a section for I/O (and perhaps more sections). From the software it looks all like memory but the hardware starts to activate certain parts of the hardware.

It's a very noisy read to dive into Linear and Real Memory Space section, start reading about MMU immediately, followed by "but we don't need an MMU anyway"

Although 32 bit microcontrollers have a real and linear address space

I don't think there is any audience which is interested in making the distinction between "real" and "virtual" or "linear" and "non-linear" address spaces.

The point is not that the address space is so big that there is space remaining for memory mapped I/O. Instead there is 1. RAM 2. memory mapped I/O therefor it must follow that a sufficiently large memory space is required to address both.

--

When we write to a variable which lives at address 0x2000_1234, what happens internally is that some logic detects the upper portion of the address (0x2000 in this example) and then activates the RAM so that it can act upon the lower portion of the address (0x1234 in this case).

In general this section is littered with too many addresses and too many internals.

Suggested rewrite of section "Linear and Real Memory Space" rename to "Memory mapped input output".

Communication between the CPU and other (on-chip) hardware has to be done with reads and writes. Choosing which hardware will be chosen at any point in time is done through addressing. The right address has to be put in the right CPU register before a decision can be made which hardware to activate for the read or write. Programming languages and libraries provide helpful abstractions so that the programmer doesn't need to think in literal addresses. Addresses are usually denoted as hexadecimal numbers like `0x0FF0`, or a longer number, depending on how many addresses there are.

Rust also provides these abstractions. One of the helpful tools in the rust eco-system is `svd2rust`. This takes a `svd` file with definitions which hardware has what address and produces rust code for us. 
<...  insert some more things which rust offers if there are any ...>

All addresses combined are usually called "address space" or "address map" or "memory map". Generally the address space can be divided for three different types of hardware:

1. A section where the program instructions are stored. These instructions are usually only loaded (reading) from memory. Traditionally this memory was only written once during the manufacturing of the embedded device. Therefor this memory is often referred to as Read Only Memory (ROM), even though modern micro controllers allow reprogramming.

2. A section where the program can store (temporarily) store some data it's working on. This memory for this is always almost Random Access Memory (RAM). This includes both stack (static) allocated data, this is memory of which the size is determined during program compilation. And heap (dynamic) allocated data, which is memory reserved when the program is running.

3. All other hardware. For example read and write from a SPI bus. Read out on-chip ADC values.

When doing programming for the desktop these hardware details are usually hidden. When programmers think of memory they usually think of heap allocated memory. Therefor it might come as a surprise that other types of hardware can be accessed through the same mechanism.

Below you can find a picture of an address map, you will see that there can be many types of memories connected to the CPU together with other hardware. The address map has to reserve addresses for hardware on the chip but also for external hardware that can be connected through the pins on the chip.

<.. picture of address map ..>

Interfacing with external hardware is often done with a protocol implemented in hardware such as I2C or SPI. Because some protocols are implemented as hardware, they can be faster, more energy efficient. Also they are more convenient to use from software because we get to keep the simple read and write operations. It's possible to implement protocols in software and control the pins on the chip, this is called [Bit banging](https://en.wikipedia.org/wiki/Bit_banging), but we will not cover how to do that in this book.

When referring to the section of the address space for a hardware component from a CPU's perspective, for example an ADC. We can call this section the "ADC address space". This is important because each seperate piece of hardware will define it's functionality together with it's own addresses. In practice you will often see that the upper bits of the address are defined by the CPU, and the lower bits by the communicating hardware. For example the CPU will reserve address 0x200 to 0x300 for an SPI device connected on the pins of the micro controller. Then the SPI device has an address space of 0x300 - 0x200 = 0x100 to implement it's own functionality.

Most of the time the address space is used for reading and writing data as well as reading and writing configuration. Often hardware components can change functionality, like speed, depending on the configuration written to it. Below you can see a picture of how an address space is used to set the speed of an SPI device.

<.. picture of frequency configuration ..>
Dominant language
No language data
Stars
1.3k
Forks
223
PR merge metrics
No merged PRs in 30d

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from rust-embedded/book

All issues in rust-embedded/book

Similar issues

More Documentation issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.