Page 1 of 4 The Pi 5 has SPI but for direct access to its hardware you need to use GPIO 5. This is an extract from the Raspberry Pi 5 IoT In C: Drivers and Gpio5.
Raspberry Pi 5 IoT In C Drivers and Gpio5
By Harry Fairhead
 Buy from Amazon.
Contents
- The Pi 5 For The IoT
- C and Visual Studio Code
- Drivers: A First Program
- The GPIO Character Drive
- GPIO Using I/O Control
- GPIO Events
- GPIO Hardware With Gpio5
Extract: GPIO Registers Extract: GPIO5
- Some Electronics
- The Device Tree
- Pulse Width Modulation
Extract: PWM Using GPIO5
- SPI Devices
Extract: SPI with GPIO 5
- I2C Driver and Gpio5
Extract: I2C with Gpio5 ***NEW!
- Sensor Drivers – Linux IIO & hwmon
- 1-Wire Bus
- The PIO
Extract: Starting PIO
- Going Further With Drivers
- Appendix I Gpio5
<ASIN:1871962943>
The Pi offers two standard ways of connecting more sophisticated devices in hardware – the Serial Peripheral Interface or SPI bus and the I2C or I-squared-C bus. In addition there is a Linux driver which supports the non-standard 1-Wire bus in software. The following chapters focus on these buses rather than specific devices. The advantage of a bus is that, once you know how to use it, connecting compatible devices is more or less the same task, irrespective of device.
There are drivers for some specific SPI devices and if such a driver exists you should use it. More information on how to do this is given later. However, if a driver doesn’t exist it isn’t difficult to interface to an SPI device at a lower level via the Linux SPI driver. First, however, we need to know something about how SPI works. If you just want to use a device driver, skip this section until you need it.
In chapter but not in this extract
- SPI Bus Basics
- SPI Interfaces
- SPI Protocol
- SPI Driver
- SPIDev
- A Loopback Example
SPI with Gpio5
You can avoid the use of a driver by working directly with the SPI hardware directly via an extended Gpio5. The only problem is that this is not well documented by Raspberry Pi. The hardware is based on the Synopsys DW_apb_ssi SPI implementation and the registers and other details are described in the company’s databook, which you can find by searching the web or as a download from this book’s web page at www.iopress.info. This document details all of the registers and their detailed function. The only problem is that there are a lot of registers and it is intimidating to getting started. Fortunately, most of the registers are set to a reasonable configuration on system reset for an SPI master and so the number of registers you actually have to interact with at first is much smaller than you might expect. It is easy to construct a struct to access the registers:
volatile typedef struct{
int32_t CTRLR0;// frame format, clock polarity, phase
int32_t CTRLR1;
int32_t SSIENR; //enable/disable
int32_t MWCR;
int32_t SER; // slave CS enable
int32_t BAUDR; // baud rate - clock divisor
int32_t TXFTLR;
int32_t RXFTLR;
int32_t TXFLR;
int32_t RXFLR;
int32_t SR; // status register
int32_t IMR; // interrupt mask register
int32_t ISR;
int32_t RISR;
int32_t TXOICR;
int32_t RXOICR;
int32_t RXUICR;
int32_t MSTICR;
int32_t ICR;
int32_t DMACR;
int32_t DMATDLR;
int32_t DMARDLR;
int32_t IDR;
int32_t SSI_VERSION_ID;
int32_t DR; // data register
int32_t DRx[35];
int32_t RX_SAMPLE_DLY;
int32_t SPI_CTRLR0 ;
int32_t TXD_DRIVE_EDGE;
}SPIregs;
The registers that are most useful have comments indicating what they do. It is worth mentioning that the data register DR is duplicated in DRx 35 times and you can use any of these registers to read or write the next data value in the FIFO buffers.
The addresses of each block of SPI registers is given in the documentation:
typedef SPIregs *SPI;
#define RP1_SPI0_BASE 0x050000
#define RP1_SPI1_BASE 0x054000
#define RP1_SPI2_BASE 0x058000
#define RP1_SPI3_BASE 0x05c000
#define RP1_SPI4_BASE 0x060000
#define RP1_SPI5_BASE 0x064000
#define SPI0 ((SPI)( PERIBase+RP1_SPI0_BASE/4))
#define SPI1 ((SPI)( PERIBase+RP1_SPI1_BASE/4))
#define SPI2 ((SPI)( PERIBase+RP1_SPI2_BASE/4))
#define SPI3 ((SPI)( PERIBase+RP1_SPI3_BASE/4))
#define SPI4 ((SPI)( PERIBase+RP1_SPI4_BASE/4))
#define SPI5 ((SPI)( PERIBase+RP1_SPI5_BASE/4))
#define SPIClock 200000000
Following the Pico SDK, the constants SPIn have been defined and these are used as pointers to the registers for each SPI channel.
|