When the AVR communicates with other devices, we need to choose which method to use. You can use classic serial ports such as UART and I2C, or you can choose the serial peripheral interface (SPI). I prefer the SPI bus method. So let's talk about this bus form.
relation
An important concept in SPI is the master-slave relationship. One device acts as the master, responsible for generating the clock signal and initiating each communication. Other devices act like the master in many ways except for the clock, and only respond when called.
In general, the SPI bus consists of at least four wires - that is, it requires four pins on each device. They are:
● MOSI: Master Out, Slave In - Data is transferred from the master to the slave.
● MISO: Master In, Slave Out - used for data transfer from slave to master.
● SCK: Clock line, sometimes also marked as CLK.
● SS: Slave Select - Sometimes also labeled Chip Select (CS); this line activates the slave and initiates communication.
Unlike other buses, the SPI bus always has only one MOSI, one MISO, and one SCK. But the bus is designed to connect multiple devices. There is only one master device on each bus (unlike I2C, which provides multi-master mode). But you can have multiple slave devices, each of which needs its own SS line.
This is considered one of the weaknesses of SPI, especially when you try to use a microcontroller with a low number of GPIOs. It requires at least four pins to be connected to a slave device, and another pin for each additional slave device. However, this bus method is very simple and the communication speed can be very fast.
Dedicated hardware
Speaking of GPIO pins, it is possible to implement a kind of "software emulated serial" style of SPI using any GPIO pin. In fact, I have done this when using devices such as shift registers. However, you will be responsible for toggling the clock pin to generate the necessary pulses and shift the data in or out of the data pins. This isn't hard, but devices like AVR microcontrollers already have the hardware built in to do all of this for you.
I used an ATMEGA328P for my experiments, so I'll point to that, but all of this should transfer easily to other microcontrollers. Let's take a look at the pinout for the ATMEG328P.
In the bottom right corner you'll see four pink labels indicating that pins 16-19 are our SPI pins. Of course, they are also normal GPIO, but when the SPI function is enabled, they take on the role of SPI, as we'll see later. By using these pins for their assigned purpose, you'll need to do less work in your code.
The difference is the SS pin. To be honest, you are pretty arbitrary with this GPIO. Even with SPI enabled, you still have to set the SS pin as an output and switch it high or low at the right moment. If you want to use another pin, it's your choice. If you want to connect more than one slave device, you have to use another GPIO.
Transferring Data
Before we discuss how to use SPI, let's take a moment to consider how it works.
You can think of the SPI portion of each device (master and slave) as a shift register, with one bit going in and one bit going out at a time on each clock pulse.
When the clock ticks, one bit is sent from the master's shift register to the slave and the rest of the bits are shifted. The slave's shift register has enough space to accept this bit because on the same clock pulse, the slave has already sent a bit of data to the master and it is also shifted along. After eight clock pulses, the two devices have exchanged all the bytes in these shift registers.
That's the secret of SPI: whenever the master sends data, it gets it back, whether or not the data makes sense (usually it doesn't). In fact, there are many times when the master just wants to prod the slave into giving up some data, and it does this by sending anything. It can be all 0s or all 1s, it doesn't matter - it's just a way to get the slave to send whatever it has in its shift register ready.
Enable SPI
Like many things on a microcontroller, SPI is controlled through clever use of registers. As usual in AVR, macros (via avr/io.h) define the registers and the bits within them, so we can simply use these names to deal with the interface.
We won't cover SPI in detail here, but we will look at the key elements that will allow you to have a simple SPI solution. Our focus will be on using an AVR as a master device.
SPCR - SPI Control Register
SPCR is the key register to establish SPI. All eight bits are used to configure the interface, which are:
According to the datasheet, when the ATMEGA328P is powered up, SPCR is set to 0. Personally, I don't mind spending a clock cycle or two writing this at the beginning of my SPI setup routine:
1SPCR = 0;
Let's take a look at what these bits mean:
● SPIE - SPI Interrupt Enable. When this is set to 1, an SPI interrupt is triggered whenever another bit in another register (SPIF in SPSR to be precise) is set.
● SPE - SPI Enable. This is critical as it effectively turns on the SPI and causes these pins to assume the SPI role.
● DORD - Data Order. This controls whether data is sent Most Significant Bit (MSB - i.e. bit 7) or Least Significant Bit (LSB, bit 0) first. In the default state (0) it is MSB, which is how I like it. Set this to 1 for Little-Endian if you roll that way or the slave device expects it.
● CPOL, CPHA - Clock Polarity and Clock Phase. These require a bit more explanation, but we’ll get to them shortly.
● SPR1, SPR0 - SPI clock frequency. These are used with the SPI2X bits in the SPSR register to set the clock speed, and therefore the rate at which data is moved. This is a prescaler related to the processor's oscillator clock frequency (Fosc).
Phase and polarity
The clock polarity and phase settings depend on how the slave operates and what is expected. There are four modes:
You need to read the datasheet of the slave device to understand its requirements. For example, I recently messed around with a 23LCV512 serial RAM chip. Its datasheet states the following:
The device is accessed via the SI pin, with data being clocked in on the rising edge of SCK.
Data being "latched" (aka latched or sampled) on the rising edge means it has to be either Mode 0 or Mode 3 from the table above. It depends on whether the rising edge is considered "leading" or "trailing." How do you know? Go back to the datasheet. It should show the timing diagram. Here's an example for our RAM chip:
See how the SCK line goes low before everything starts in the input version? The 'MSB' occurs when SCK goes high. So the rising edge here is also leading, which means we want pattern 0, also known as 0,0 in many circles.
Setting the speed
Setting the SPR0 and SPR1 bits in the SPCR and the SPI2X bits in the SPSR sets the clock frequency to a fraction of the specific frequency of the oscillator used to run the microcontroller (Fosc). So if you run your processor at 16MHz like I do, and set a prescaler value (like 16), the SPI bus will run at 1MHz. The larger the prescaler value, the slower the SPI bus.
You might think you want to go as fast as possible, but you might run into problems, especially if the wires to your slaves are long. As I do a lot of this stuff on a breadboard, I tend to use the second slowest 64-bit setting, presuming that I can always try to increase the speed.
SPSR - SPI Status Register
We only care about three bits here, and if I'm honest, I'm mainly concerned with only one bit.
● SPIF - SPI interrupt flag. Automatically set when data transfer and input is complete. If you have enabled global interrupts and the SPIE bit in SPCR, an interrupt will be triggered when this flag is set. Handling the interrupt will automatically clear the flag, as will reading the SPI data register (SPDR). So in most cases, you only need to read this flag.
● WCOL – Write Collision Flag.
● SPI2X - Part of the clock speed setting.
Preparing for setup
Before we examine the third register, let's set up the SPI. I'm going to assume that the AVR will be acting as a master, that we won't be messing with interrupts, and that the data order will be MSB first. The serial RAM chip I'm going to be communicating with has a clock polarity (CPOL) of 0 and a clock phase (CPHA) of 0. I'm going to use 1/64 of the processor speed as the bus speed.
Let's configure the eight bits of the SPCR. I'll go through all eight bits - even the ones I'm not using - and you can see:
SPCR = 0; // just to be sure
// SPCR |= (1 << SPIE); // not using interrupts, so leaving this at 0
SPCR |= (1 << SPE); // enable SPI
// SPCR |= (1 << DORD); // we want to keep the default MSB first, so not using this
SPCR |= (1 << MSTR); // set master mode
// SPCR |= (1 << CPOL); // leaving this set to 0
// SPCR |= (1 << CPHA); // leaving this set to 0
SPCR |= (1 << SPR1); // using a prescaler setting of 64 (1,0) in this register
// SPCR |= (1 << SPR0);
With this we are ready. In Part 2 we will start using the SPI bus.
Previous article:AVR Basics: The ATMEGA's SPI Bus - Part 2
Next article:Make a four-channel thermometer based on ATtiny85 microcontroller
- Popular Resources
- Popular amplifiers
- Learn ARM development(16)
- Learn ARM development(17)
- Learn ARM development(18)
- Embedded system debugging simulation tool
- A small question that has been bothering me recently has finally been solved~~
- Learn ARM development (1)
- Learn ARM development (2)
- Learn ARM development (4)
- Learn ARM development (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- Detailed explanation of intelligent car body perception system
- How to solve the problem that the servo drive is not enabled
- Why does the servo drive not power on?
- What point should I connect to when the servo is turned on?
- How to turn on the internal enable of Panasonic servo drive?
- What is the rigidity setting of Panasonic servo drive?
- How to change the inertia ratio of Panasonic servo drive
- What is the inertia ratio of the servo motor?
- Is it better for the motor to have a large or small moment of inertia?
- What is the difference between low inertia and high inertia of servo motors?
- Understanding Nginx Architecture in One Article
- Highly recommended! ADI's latest Chinese information is here
- Urgently looking for expert advice AD15 can not open the PCB after cracking
- Difference between LPS22HH and LPS22HB
- How to collect multiple sensor signals through one RS485 interface of industrial computer?
- Altera SoC Architecture Excerpt - What is a SoC FPGA
- How to use common mode chokes in signal lines to eliminate common mode noise
- EEWORLD University ---- Python 3 video tutorial
- [Rivet RVB2601 Creative Application Development Competition] Participation Award Prizes
- CCS5.5 compiler optimization issues