rust-embedded / book

Documentation on how to use the Rust Programming Language to develop firmware for bare metal (microcontroller) devices
https://docs.rust-embedded.org/book/
Apache License 2.0
1.08k stars 172 forks source link

Peripherals #155

Open flip111 opened 5 years ago

flip111 commented 5 years ago

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:

And the following would be left undiscussed:

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 ..>
flip111 commented 5 years ago

I will make a PR for this maybe

therealprof commented 5 years ago

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.

That's not accurate. I think the problem is that the incorrect use of the word microcontroller in the context: A peripheral is anything that connects to the processing core(s) to extend the functionality or connect to the outside world (hence the mention of APB, AHB, etc. in the datasheets).

flip111 commented 5 years ago

@therealprof In the text "Peripheral" is opposed to "CPU, RAM, or Flash Memory" because when describing peripherals it's contrast it with that because of the wording "more than just".

A peripheral is anything that connects to the processing core(s) to extend the functionality or connect to the outside world

Is this the alternative definition you provide? I didn't understood this.

I just like to avoid the word peripheral if it gets ambiguous. Or else use the manner in which it's used most in lecture, even if people use it wrongly.

adamgreig commented 5 years ago

This issue covers quite a few different parts of the chapter. I think you've highlighted some good examples of where we could be clearer with language or things could be explained better. On the other hand I strongly feel like "peripheral" is the correct word to describe on-chip components such as the ADCs, DMA, CRC block, timers, GPIO, comparators/opamps, etc etc. The datasheets and reference manuals do this, Wikipedia does this, it's common vernacular for embedded development.

For example, the STM32F405 datasheet:

image

Our description of them as just "used for interacting with systems outside of the microcontroller" could be made more broad (you're right in that the CRC etc wouldn't be covered by this), and the description of offloading processing likewise could be expanded (it makes sense to talk about offload with the CRC peripheral or with the DMA or even SPI/I2C when you could bitbang those in software; we don't use offload to refer to the GPIO or ADC so much).

I'll leave off discussion of the memory map bit for now.

therealprof commented 5 years ago

@flip111 Peripherals are additions hooked up to a bus to provide extra functionality. With MCUs they're usually built into the same chip and the busses are not exposed externally in contrast to a general purpose CPU which contains few or no built-in peripherals but exposes one or more busses so external chips can (or have to be used) to provide peripherals.

flip111 commented 5 years ago

On the other hand I strongly feel like "peripheral" is the correct word to describe on-chip components such as the ADCs, DMA, CRC block, timers, GPIO, comparators/opamps, etc etc. The datasheets and reference manuals do this, Wikipedia does this, it's common vernacular for embedded development.

Yes i totally agree with this. Excuse me this was not clear or if i'm backtracking a bit on my words. I actually see that i wrote the wrong thing. Instead of:

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

I should have written:

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

because i tripped over the part outside of the microcontroller