直接访问树莓派的SPI,不通过驱动程序
/dev/mem是物理内存的全映像,可以用来访问物理内存,一般用法是open("/dev/mem",O_RDWR|O_SYNC),然后mmap,接着就可以用mmap的地址来访问物理内存,这实际上就是实现用户空间驱动的一种方法。
pispi.h:
1 #ifndef PI_SPI_H 2 #define PI_SPI_H 3 4 #define SPICLKDIV 32 /* ~8 Mhz */ 5 6 #define SPIBUFSIZE 32 /* SPI buffer size */ 7 #define BUFSIZE (SPIBUFSIZE/4) 8 9 /* Broadcom defines */ 10 11 #define BCM2835_PERI_BASE 0x20000000 12 #define BCM2835_GPIO_BASE (BCM2835_PERI_BASE + 0x200000) /* GPIO controller */ 13 #define BCM2835_SPI_BASE (BCM2835_PERI_BASE + 0x204000) /* SPI controller */ 14 15 #define BCM2835_GPFSEL0 *(gpio) 16 #define BCM2835_GPFSEL1 *(gpio + 1) 17 #define BCM2835_GPFSEL2 *(gpio + 2) 18 19 #define BCM2835_SPICS *(spi + 0) 20 #define BCM2835_SPIFIFO *(spi + 1) 21 #define BCM2835_SPICLK *(spi + 2) 22 23 #define SPI_CS_LEN_LONG 0x02000000 24 #define SPI_CS_DMA_LEN 0x01000000 25 #define SPI_CS_CSPOL2 0x00800000 26 #define SPI_CS_CSPOL1 0x00400000 27 #define SPI_CS_CSPOL0 0x00200000 28 #define SPI_CS_RXF 0x00100000 29 #define SPI_CS_RXR 0x00080000 30 #define SPI_CS_TXD 0x00040000 31 #define SPI_CS_RXD 0x00020000 32 #define SPI_CS_DONE 0x00010000 33 #define SPI_CS_LEN 0x00002000 34 #define SPI_CS_REN 0x00001000 35 #define SPI_CS_ADCS 0x00000800 36 #define SPI_CS_INTR 0x00000400 37 #define SPI_CS_INTD 0x00000200 38 #define SPI_CS_DMAEN 0x00000100 39 #define SPI_CS_TA 0x00000080 40 #define SPI_CS_CSPOL 0x00000040 41 #define SPI_CS_CLEAR_RX 0x00000020 42 #define SPI_CS_CLEAR_TX 0x00000010 43 #define SPI_CS_CPOL 0x00000008 44 #define SPI_CS_CPHA 0x00000004 45 #define SPI_CS_CS_10 0x00000002 46 #define SPI_CS_CS_01 0x00000001 47 48 #define BLOCK_SIZE (4*1024) 49 50 #endif 51
pispi.c
/* Copyright (C) 2015 Zhang Wei * * Read write Raspberry Pi SPI without SPI driver * */ #include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <sys/mman.h> #include "pispi.h" volatile unsigned *gpio, *spi; volatile unsigned txBuf[BUFSIZE], rxBuf[BUFSIZE+1]; static int map_gpio(); static void setup_gpio(); static void restore_gpio(); static void transfer_data(); int main(int argc, char *argv[]) { /* put "HELLO, WORLD\n" in txBuf */ txBuf[0] = 0x4C4C4548; //0x48454C4C; "HELL" reversed txBuf[1] = 0x57202C4F; //0x4F2C2057; "O, W" reversed txBuf[2] = 0x444C524F; //0x4F524C44; "ORLD" reversed txBuf[3] = 0x2020200A; //0x0A202020; "\n " reversed map_gpio(); setup_gpio(); transfer_data(); restore_gpio(); munmap((void *)gpio, BLOCK_SIZE); munmap((void *)spi, BLOCK_SIZE); return 0; } int map_gpio() { int fd; fd = open("/dev/mem", O_RDWR | O_SYNC); if (fd < 0) printf("can't open /dev/mem \n"); /* mmap GPIO */ gpio = mmap( NULL, BLOCK_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, BCM2835_GPIO_BASE); if (gpio == MAP_FAILED) { printf("can't map gpio \n"); close(fd); return -1; } /* mmap SPI */ spi = mmap( NULL, BLOCK_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, BCM2835_SPI_BASE); close(fd); if (spi == MAP_FAILED) { printf("can't map spi\n"); return -1; } return 0; } void setup_gpio() { unsigned int x; /* change SPI pins */ x = BCM2835_GPFSEL0; x &= ~(0b111 << (9*3)); x |= 0b111 << (9*3); BCM2835_GPFSEL0 = x; x = BCM2835_GPFSEL1; x &= ~(0b111 << (0*3) | 0b111 << (1*3)); x |= (0b100 << (0*3) | 0b100 << (1*3)); BCM2835_GPFSEL1 = x; /* set up SPI */ BCM2835_SPICLK = SPICLKDIV; BCM2835_SPICS = 0; /* clear FIFOs */ BCM2835_SPICS |= SPI_CS_CLEAR_RX | SPI_CS_CLEAR_TX; /* clear done bit */ BCM2835_SPICS |= SPI_CS_DONE; } void restore_gpio() { unsigned int x; /* change SPI pins to inputs*/ x = BCM2835_GPFSEL0; x &= ~(0b111 << (9*3)); BCM2835_GPFSEL0 = x; x = BCM2835_GPFSEL1; x &= ~(0b111 << (0*3) | 0b111 << (1*3)); BCM2835_GPFSEL1 = x; } void transfer_data() { char *buf; int i; /* acitvate transfer */ BCM2835_SPICS = SPI_CS_TA; /* send txBuf */ buf = (char *)txBuf; for (i=0; i<SPIBUFSIZE; i++) { BCM2835_SPIFIFO = *buf++; } /* wait until transfer is finished */ while (!(BCM2835_SPICS & SPI_CS_DONE)); /* clear done bit */ BCM2835_SPICS = SPI_CS_DONE; /* read buffer */ buf = (char *)rxBuf + 3; /* ignore 1st byte and align data */ for (i=0; i<SPIBUFSIZE; i++) { *buf++ = BCM2835_SPIFIFO; } }