Embedded system development involves frequent contact with hardware. A certain understanding of both digital and analog circuits is necessary for in-depth research. Below, we briefly introduce some hardware-related concepts in embedded development.
Bus
In any embedded system, there will always be a processor chip. In addition, there are other chips that act as external devices (hereinafter referred to as peripherals). These chips work with the processor to realize the product's functions. Complex products are often composed of a large number of chips. Therefore, it is inevitable that we need to connect all peripherals to the processor. The simplest solution is to connect all peripherals to the processor using independent (note that it is independent) signal lines. The advantage of this is easy to understand, but the problem is: it is not feasible.
Because processor chips would require too many leads, it's impractical from both chip manufacturing and product production perspectives. Furthermore, processors (assuming they are single-core, not multi-core) process transactions serially at the microscopic level. This means that at any given moment, if a read/write operation is needed on a peripheral, it can only be performed on one of many peripherals; multiple peripherals cannot be accessed simultaneously by the processor at the microscopic level.
It's important to note that the concept of "microscopic" is introduced here to distinguish it from "macroscopic." From a macroscopic perspective, a processor can have multiple tasks running simultaneously, but at the microscopic level, these tasks run one by one (the term "one by one" will be used later to describe this). The serial execution of multiple tasks is implemented by the operating system, which plays a crucial role in this process.
Returning to our topic, since connecting each peripheral to the processor with a separate signal line is not feasible, and the processor will only access one peripheral at a time, could we connect all the chips together using a shared signal line? This is the origin of the bus concept. In simple terms, if we have ten households around us, to allow communication between any two households, we don't need to build a separate road for each pair of households (note the emphasis on separate roads; otherwise, we would need 45 roads). Instead, we can build a main road, and then connect each household to that main road.
Regarding the bus, we often say that the bus belongs to the processor, while other peripherals are connected to the bus. But here's the problem: we can only access one peripheral connected to the bus at a time. So how do we distinguish these peripherals? Just like with roads, we need addresses to distinguish each "home." On the bus, addresses are also used for differentiation.
Thus, buses are divided into two categories based on their functions. One is the address bus, where data only flows from the processor to the peripheral device; it's unidirectional. The other is the data bus, used to transfer data from the processor to the peripheral device (a write operation from the processor's perspective) or from the peripheral device to the processor (a read operation from the processor's perspective). Obviously, the data bus is bidirectional. In other words, our embedded system has both address and data buses, connecting all the chips that need to communicate with the processor.
A data bus has a width, just as a road may have three or four lanes. When we say a 32-bit processor, we mean its data bus width is 32 bits, meaning "32 cars can run simultaneously." Obviously, the wider the bus, the faster the processor, because we can access data from peripheral chips much faster. This is why our computers have evolved towards 64-bit architecture. Similarly, the address bus also has a width; for a 32-bit processor, its maximum width is also 32 bits.
Now that we have the concept of a bus, the next question is: even if each peripheral has an address, where is this address stored? Is it stored on the peripheral chip itself? If so, there's a problem: the addresses of each type of peripheral must not overlap. However, if a product needs two identical chips, their addresses become indistinguishable, which seems problematic. Furthermore, this approach would require each peripheral to be fully connected to (e.g., 32 data lines) and listen to the data lines to determine if the processor is "calling" it, which is quite complex.
Furthermore, addresses may run out as the number of peripherals increases. In general, addresses cannot be stored on the peripheral chip itself. So how does the peripheral know that it has been invoked by the processor and requires read/write access? The answer is the chip select (CS) signal, or the enable signal.
Film selection (CS or EN)
For a peripheral chip, the chip select signal is essentially a notification signal, telling the chip, "Hey, open the door, I need to put something in or take something away." This "something" can only be data, not something like a corncob. So, where does this signal come from? Clearly, it can only come from the processor. Does that mean, like a bus, all chips share a single wire for connection?
If this were the case, all the chips might open their "doors" as soon as the processor "calls for opening." If the processor is writing data, all the chips might be written with the same data. When retrieving data, each peripheral chip would "throw" data out, inevitably causing data bus conflicts, because some chips would "throw" 1s onto the bus while others would "throw" 0s. In this situation, the processor would definitely "go crazy" because it wouldn't know whether it should receive a 1 or a 0.
Given this, it's clear that we can't connect all the chip select signals together; each chip's chip select signal must be independent. We mentioned the address bus earlier. Should we use one address line to connect one peripheral chip, or should we use another method? If we use one address line to connect one peripheral chip, we could only connect a maximum of 32 chips, which is obviously not feasible.
In reality, a peripheral chip's address is represented using 32-bit numbers. For example, 1 can represent chip A, while 6534 can represent chip B, and so on. Therefore, theoretically, we can represent 2^32 (4,294,967,296) devices. The reason for saying "theoretically" is that some devices require a large number of addresses. Given this, another question arises: how do we convert the 32-bit address bus into a single chip select signal? This requires introducing the concept of a decoder.
Decoder
A decoder converts data into a signal on a single signal line. For example, a 3/8 decoder can convert 3-bit data into 8 completely independent signal lines (2^3). When writing binary 011 to the data side, it corresponds to the 3rd of the 8 lines; when inputting binary 111, it corresponds to the last of the 8 lines. With a decoder, the processor's address lines are simplified. With just 32 address lines and an external decoder, a large number of peripheral chips can be accessed. We have solved the problem of selecting external devices; now we need to look back at the data bus.
Figure 13/8 Decoder
In embedded systems, the data buses of all chips can be understood as being directly connected. The reason for using the word "understandable" is that bus drivers are added to increase the load capacity of the bus. To understand this, let's look at tap water in our daily lives. For example, in Beijing, theoretically all water pipes may be connected together, but in order to increase water pressure, there may be many small water stations to increase the water supply pressure. It is impossible for all the tap water in Beijing to come directly from a single water treatment plant.
Since all the data buses are connected, there might be a problem. When writing data to an external device, the processor first sends the address of the target peripheral to the address bus. The address decoder converts this into a chip select signal, which is then sent to the target peripheral. Upon receiving this signal, the target peripheral opens its "gate." Next, the processor places the data to be transmitted to the peripheral onto the data bus. Because only the target peripheral chip has its "gate" open, the data only enters the target peripheral, and other peripherals receive nothing. Great! The processor should have no problem writing data. Let's look at reading next. For reading, since the data is transmitted from the peripheral to the processor, even though we use the same method to open the target peripheral's "gate" as for writing, other peripherals are also on the data bus at this time. They might be in a 1 or 0 state. Will this affect the processor's ability to read data from the target peripheral? The answer is no, but we need to introduce another concept: high impedance state.
High resistance state
Obviously, when the processor reads data from the target peripheral, we want the data buses of other unselected chips not to affect the data being transmitted by the target peripheral. How do we achieve this? In fact, when a chip is not selected, its data bus is in a high-impedance state. A high-impedance state can be understood as the pin being disconnected internally within the peripheral chip. Therefore, it obviously won't affect the processor's data reading from the target peripheral. We say that when a chip is not selected or enabled, its data bus is always in a high-impedance state. We used the analogy of "gates" to illustrate this; what do these "gates" refer to? They refer to the peripheral's data bus. The chip select signal controls whether the peripheral's data bus is connected to or disconnected from the processor's data bus. For more explanation of high-impedance states, please refer to the previous article, "High-Impedance State and Tri-State Gates."
drive
The device that puts data onto the bus is considered the driver at any given moment. That is, when the processor writes data to a peripheral, it drives the data bus; when the processor reads data from a target peripheral, the target peripheral drives the data bus. For the address bus, since writing can only be done from the processor to the target peripheral, the address bus is always driven by the processor. When a chip is not selected, we say it does not drive the data bus.
Three-state gate
As mentioned earlier, the data bus of a peripheral chip is in a high-impedance state when it is not selected, and its level can be high (1) or low (0) when selected. Therefore, we say that the chip pins of the peripheral's data bus are tri-state gates, meaning they exist in three states: high level, low level, and high impedance. For more information on tri-state gates, please refer to the previous article, "High Impedance State and Tri-state Gates".
Level validity
We've previously learned about chip select signals and discussed tri-state gates. It's important to note that chip select signals are typically not tri-state gates; they only exist in two states: high or low. As mentioned, chip select signals are used to "open" the gate, and since they have high and low levels, does a high level represent "open" or a low level? To answer this, we say that if a level represents "open" for a chip select signal, then that level is the valid level for that signal. For example, if a low level represents "open" for a chip select signal, then we say that the chip select signal is valid (low level). Although we've used chip select signals to explain the validity of levels here, many signals have validity issues. For example, the read and write signals, which we'll discuss later, also have validity issues.
Time series
As mentioned earlier, when a processor needs to write data to a peripheral chip, it first places the address of the desired peripheral on the address bus. Then, the decoder converts the data on the address bus into a chip select signal, which enables the target peripheral chip. Next, the processor writes the data to the data bus, completing a write operation. Clearly, the data on the address lines must be retained for a period of time before the processor writes the data to the data bus; otherwise, the decoder cannot keep the chip select signal valid for an extended period. After the data write operation is complete, the processor no longer needs to ensure the address on the address bus is valid. We can see that this series of operations has a strict time sequence, which is called timing. Timing describes the "procedure" of interaction signals between the processor and external devices. Only by following this "procedure" can normal communication between the processor and external devices be guaranteed. This is similar to traffic lights on our roads; if pedestrians and vehicles do not follow the instructions, accidents will occur. Typically, timing diagrams are used to describe the signal "procedure" of communication between chips.
ADDRESS represents the address bus, DQ represents the data bus, and CE is the chip select signal, which is active low and its width must be sufficient to ensure it is always active during read operations. Learning to read timing diagrams is extremely helpful for embedded system development, as we inevitably interact with chips. Timing diagrams typically indicate a lot of timing requirements. When writing startup code, it's necessary to initialize the chip select address registers and read/write timings for each address space. The timing configuration is based on the timing requirements of the peripheral chips, which is a crucial part of the chip's datasheet. When multiple peripheral chips exist in an address space, we need to consider the timing requirements of the slowest peripheral chip; otherwise, some chips will not function properly.
Read signal
When the processor needs to read signals from a peripheral chip, in addition to generating a chip select signal, it also needs to tell the peripheral chip that this is a read operation, not a write operation. This is achieved through the read signal.
Write signal
Having discussed the read signal, the write signal should be easy to understand. This signal tells the peripheral chip that it is an operation to write data to the peripheral chip.
I/O ports
Having mentioned peripherals (chips), it's time to categorize them. Broadly speaking, peripherals fall into two categories: memory peripherals and non-memory peripherals, often referred to as I/O devices. I/O stands for Input/Output. As you can see, I/O peripherals are a very broad concept. Memory peripherals are characterized by occupying a contiguous block of memory. For example, SDRAM memory is a memory peripheral; if its capacity is 8MB, then it will occupy 8MB of address space.
Unlike memory peripherals, I/O peripherals typically use a limited number of addresses. For example, an I/O peripheral may have multiple control registers. From the processor's perspective, these control registers are multiple I/O ports (addresses). Writing data to this address means writing data to the corresponding register of the peripheral, and vice versa. For instance, a serial port chip may have multiple registers: one for querying the chip's status, one for setting the chip's functions, another for reading data received from the serial line, and finally, another for writing data to the chip to send data over the serial line. From the processor's perspective, each register of this serial port chip is an independent I/O port.
I/O ports have read/write capabilities; some ports are read-only, some are write-only, and others can be both read and write. Their read/write capability is determined by the registers of the peripheral chip, which can be found in the chip's datasheet. It should be noted that some memory peripherals also have I/O ports for certain control purposes. As the name suggests, for the processor, an I/O port is a general term for an interface for reading data from or outputting data to external devices.
Interruption
From a hardware perspective, an interrupt is simply a signal line that generates high and low voltage levels. However, understanding it requires considering the processor's perspective. As we've discussed, from a microscopic standpoint, the processor performs its work sequentially, executing instructions one at a time. If there's a need to access a peripheral chip, and the processor issues a read or write command, the peripheral chip typically needs time to prepare the required data, as peripherals are usually much slower than processors. In this situation, if the processor waits for the peripheral chip to return data before executing subsequent instructions, it wastes valuable time that could be used for other tasks.
Don't forget that, from a macroscopic perspective, processors are often multitasking; a task is a scheduling unit provided by the operating system. When a task is blocked waiting for data from a peripheral chip, we can switch to another task to improve processing efficiency. This raises a question: when the processor is handling another task, how do we notify the processor if the peripheral chip's data is ready? That's right! It's through interrupt signals. The high and low levels of interrupt signals can be used to indicate whether an interrupt needs the processor's attention to handle a specific event (such as the event that peripheral data is ready).
Therefore, the introduction of interrupts can greatly improve the efficiency of the processor. To use interrupts on the processor, we first need to initialize the processor's interrupt controller, such as installing the required interrupt service routines (ISRs) and then enabling the interrupt mask. The interrupt service routines need to perform the following operations:
1. Reading data from or writing data to a peripheral device. Whether to read or write is usually determined by reading the peripheral device's interrupt status register.
2. Clear the peripheral's interrupt signal. We know that interrupt signals are driven by the peripheral chip. To inform the peripheral chip that the processor has completed its work, the processor needs to notify the peripheral chip in a certain way. This is done by writing a data bit to a specific bit in the peripheral chip's register. For example, writing a 1 indicates clearing the interrupt, or writing a 0 indicates clearing the interrupt; this information can usually be found in the peripheral's datasheet. When the peripheral receives the processor's request to clear the interrupt, it will invalidate the interrupt line. For example, if a peripheral's interrupt line is low to indicate an interrupt, changing it from low to high will invalidate the interrupt.
3. Clear the processor's interrupt flags. Processors often store information about whether external interrupts have occurred. After handling an interrupt from a peripheral chip, we also need to clear the flags on the processor to prepare for the next interrupt. It's important to note that clearing peripheral interrupts must occur before clearing the processor's interrupt flags!
Interrupts also involve a triggering method issue. There are two triggering methods: level-triggered and edge-triggered. Level-triggered interrupts indicate whether a peripheral device has an interrupt by a high or low voltage level, while edge-triggered interrupts are indicated by a rise or fall in the voltage level on the interrupt line. Clearly, there are two edge-triggered methods: one is when the interrupt line changes from low to high, which we call rising-edge triggering; the other is when the interrupt line changes from high to low, which we call falling-edge triggering. In general, interrupts are triggered by level-triggered, rising-edge triggering, and falling-edge triggering. In level-triggered interrupts, interrupt settings are a crucial step.
multimeter
Multimeters are commonly used to check voltage levels, resistance values, and other parameters; they are essential and frequently used tools. In embedded system development, digital multimeters are the most commonly used.
Level
In digital circuits, there are high and low levels, represented by 1 and 0 respectively. A pin of a digital circuit always has one level, either high or low, or either 1 or 0 (actually, there is another state).
Oscilloscope
In embedded system development, we inevitably interact with peripheral chips. When debugging drivers, besides fully understanding the chip's datasheet, we also need to verify whether the expected signal levels are occurring on the chip during the software development process. For example, when writing drivers, we need to operate on peripheral chips by writing to I/O ports. When writing to the corresponding I/O port, we know that the chip select signal of the corresponding chip should be valid. Sometimes, we need to verify whether it has occurred as expected, which requires the use of an oscilloscope. A typical oscilloscope can simultaneously observe the signal status of two signal lines. Oscilloscopes provide certain functions, such as setting the signal capture mode, etc. A very important parameter of an oscilloscope is its sampling frequency. According to the Nyquist sampling theorem, if we want to use an oscilloscope to view a signal with a frequency of 100 MHz, then its sampling frequency must be at least twice that, i.e., 200 MHz. Some people may ask: Why not use a multimeter? Because the sampling frequency of a multimeter is very low and cannot capture fast signal changes.
Logic Analyzer
Simply put, a logic analyzer is an oscilloscope with many signal channels. Through a logic analyzer, we can see the data on the address bus and data bus. Logic analyzers offer programming capabilities, allowing you to program when to start acquiring data on the bus.
Disclaimer: This article is a reprint. If there are any copyright issues, please contact us promptly for deletion (QQ: 2737591964). We apologize for any inconvenience.