6. SPI Operation Guide¶
This documentDescriptionin CV184x on the platformUse SPI Bus Read/writeOperation、Loopback TestwithandKernel space/User space ofFlow。
PlatformDescription :CV184x onof SPI Controller Support (Master)Mode,notSupportConfigurationisfrom (Slave)Mode。 Platform is SPI Busof Device 、 Flash/ etc.fromDevice, isfromDevice Through SPI Access。 Platform SPI Support 46.8MHz,Device TreeandDriverin spi-max-frequency canConfiguration 46800000(Hz), Valuecan ornotSupport。
6.1. Preparation¶
Use SPI The following conditions must be met first:
Use of SDK BuildafterkernelImage(DefaultalreadyInclude SPI RelatedDriver)。
6.1.1. EnableKernel SPI and DMA Configuration¶
Steps is :inBoard-levelKernel Configurationin SPI and DMA RelatedOption;inDevice Treeinis SPI1 DMA;IfneedUse DMA Channel , inBoard-level DTS NodeunderConfiguration sysdma_remap。Pathinof”Board Name”PleaseReplaceisActualUseofBoard-levelDirectory Name(If cv1842hp_wevb_0014a_spinor), with SDK is 。
(1)Kerneland DMA RelatedConfiguration
inBoard-levelKernel ConfigurationFileinEnsurefollowingOptionalready 。Configuration FilePathusually build/boards/cv184x/Board Name/linux/Board Name_defconfig 。
CONFIG_DMADEVICES=y
CONFIG_DW_DMAC_CVITEK=y
CONFIG_SPI=y
CONFIG_SPI_MASTER=y
CONFIG_SPI_SPIDEV=y
CONFIG_SPI_DESIGNWARE=y
CONFIG_SPI_DW_DMA=y
CONFIG_SPI_DW_MMIO=y
IfnotNeed to DMA (for example 、 or not DMA),canwill CONFIG_SPI_DW_DMA , SPI Controller to PIO(Interrupt/ )Mode:
CONFIG_DMADEVICES=y
CONFIG_DW_DMAC_CVITEK=y
CONFIG_SPI=y
CONFIG_SPI_MASTER=y
CONFIG_SPI_SPIDEV=y
CONFIG_SPI_DESIGNWARE=y
# CONFIG_SPI_DW_DMA is not set
CONFIG_SPI_DW_MMIO=y
needinDevice Treeinwill SPI Nodeof #if 1 is #if 0,Disable DMA Attribute( under (2)inofExample)。ModifyafterRebuildKernelandDevice TreeandBurning can。
(2)inDevice Treeinis SPI1 DMA
inBoard-level DTS or Includeof DTSI in, to SPI1 Node(If spi1@04190000),will inof #if Build is 1, dmas、dma-names、capability etc. DMA RelatedAttribute Build Device Tree,from SPI1 of DMA Function。If #if is 0 or Definition , SPI1 Use PIO Mode。
spi1: spi1@04190000 {
compatible = "snps,dw-apb-ssi";
reg = <0x0 0x04190000 0x0 0x10000>;
clocks = <&clk CV184X_CLK_APB_SPI1>;
#address-cells = <1>;
#size-cells = <0>;
#if 1
dmas = <&dmac 2 1 1
&dmac 3 1 1>;
dma-names = "rx", "tx";
capability = "txrx";
#endif
status = "okay";
num-cs = <1>;
spidev@0 {
compatible = "rohm,dh2228fv";
spi-max-frequency = <1000000>; /* Support 46.8MHz,can is 46800000 */
reg = <0>;
};
};
spi-max-frequency Unitis Hz, Platform SPI IP Support 46.8MHz,Do notConfiguration 46800000。
(3)DMA Channel
IfBoard-levelNeed to DMA Channeland ofCorrespondence,caninBoard-level DTS of Node / underAddor and sysdma_remap Node。Board-level DTS Pathusually build/boards/cv184x/Board Name/dts_arm/Board Name.dts 。under in CVI_SPI1_RX、CVI_SPI1_TX and SPI1 Devicein the nodeof DMA Channel 2 and 3 , Channel Actualneed Configuration。
/ {
sysdma_remap {
ch-remap = <CVI_I2S0_RX CVI_I2S2_TX CVI_SPI1_RX CVI_SPI1_TX
CVI_SPI_NOR_RX CVI_SPI_NOR_TX CVI_I2S2_RX CVI_I2S3_TX>;
};
};
6.1.2. Enable SPI1 in the Device Tree¶
inBoard-level DTS inwill SPI1 set the node to status = "okay", notUseof SPI set the node to status = "disabled"。
6.1.3. SPI1 Pin Switching¶
Description :following”need PinFunction” is SPI1 of ( to MUX to Function)。 SPI Controlleror of Pinmux Operate according to the actual board schematic and pin definitions,can need ornot ,with pinout is 。
Steps 1. will PAD_MIPIRX3P MUX_SPI1_MOSI
cvi_pinmux -w PAD_MIPIRX3P/MUX_SPI1_MOSI
Steps 2. will MUX_SPI1_MOSI SPI1_SDO
cvi_pinmux -w MUX_SPI1_MOSI/SPI1_SDO
Steps 3. MISO Pin
Method ( to MUX_SPI1_MISO, to SPI1_SDI , withBoard-levelPinDefinitionis )。
cvi_pinmux -w PAD_MIPIRX3N/MUX_SPI1_MISO
cvi_pinmux -w MUX_SPI1_MISO/SPI1_SDI
6.2. Operation Procedure¶
System SPI RelatedDriveralready Kernel,No need to LoadModule; after canUse SPI。
SPI Read/write inSerial Portor SSH TerminalinRun SPI Read/writeCommands,orinKernel space/User space Program, in SPI ControlleronoffromDevice Read/write。
6.3. SPI Loopback Test¶
Loopback Test Verification SPI ControllerandPin :will SPI1 of MOSI and MISO , Dataafter , 。
Steps 1: SPI1 of MOSI and MISO Pin
Steps 2:Complete SPI1 Kernel ConfigurationandDevice TreeEnable
on 「Preparation」inof「EnableKernel SPI and DMA Configuration」and「Enable SPI1 in the Device Tree」 CompleteConfiguration,RebuildKernelandDevice TreeandBurning 。
Steps 3:Confirm spidev Node
ls /dev/spidev*
# ExampleOutput:/dev/spidev1.0,after CommandsinofDeviceNodeneedandOutput
Steps 4:Execute cvi_pinmux
following「need PinFunction」 is SPI1 of ( to MUX to Function)。 SPI Controlleror of Pinmux Operate according to the actual board schematic and pin definitions,can need ornot ,with pinout is 。
Steps 4.1 will PAD_MIPIRX3P MUX_SPI1_MOSI
cvi_pinmux -w PAD_MIPIRX3P/MUX_SPI1_MOSI
Steps 4.2 will MUX_SPI1_MOSI SPI1_SDO
cvi_pinmux -w MUX_SPI1_MOSI/SPI1_SDO
Steps 4.3 MISO Pin
Method ( to MUX_SPI1_MISO, to SPI1_SDI, withBoard-levelPinDefinitionis )。
cvi_pinmux -w PAD_MIPIRX3N/MUX_SPI1_MISO
cvi_pinmux -w MUX_SPI1_MISO/SPI1_SDI
Steps 5:Buildand spidev_test
in SDK oflinux_5.10/tools/spi under the directoryExecute make,willGenerateof spidev_test Copyto 。
Steps 6:GenerateTestsData
dd if=/dev/urandom of=data.bin bs=2k count=1
Steps 7:ExecuteLoopback Test
./spidev_test -D /dev/spidev1.0 -s 10000000 -i data.bin -o data_out.bin
# -D isDeviceNode,-s isRate(Hz),-i isInputFile,-o isOutputFile
Steps 8: Data
diff data.bin data_out.bin
# OutputIndicates File ,Loopback TestThrough
Loopback TestThroughafter,can Actual SPI fromDevice Read/writeOperation。
6.4. Operation Example¶
6.5. Kernel-Space SPI Read/Write Program Example¶
followingDescriptioninKernelDriverinThrough SPI SystemAccessfromDeviceof FlowandExampleCode。
FlowOverview:
Use
spi_busnum_to_master(bus_num)Get SPI Controller(spi_master),bus_numis Device inofBus 。Bus and to
spi_device``(IfThrough ``bus_find_device_by_nameetc.)。spi_transferandspi_message,spi_syncorspi_asyncExecute or 。
Steps 1:Get SPI Controller
master = spi_busnum_to_master(bus_num);
/* bus_num:Device in SPI Bus ;master:spi_master */
Steps 2:Get SPI fromDevice
snprintf(str, sizeof(str), "%s.%u", dev_name(&master->dev), cs);
dev = bus_find_device_by_name(&spi_bus_type, NULL, str);
spi = to_spi_device(dev);
/* cs: ;spi:spi_device */
Steps 3: spi_message
spi_message_init(&m);
spi_message_add_tail(&t, &m);
/* t:spi_transfer;m:spi_message */
Steps 4:
status = spi_sync(spi, &m); /* */
/* or status = spi_async(spi, &m); */
CompleteExampleCode( Refer to, can RunofCompleteModule):
1#include <linux/spi/spi.h>
2
3static unsigned int busnum;
4module_param(busnum, uint, 0);
5MODULE_PARM_DESC(busnum, "SPI bus number (default=0)");
6
7static unsigned int cs;
8module_param(cs, uint, 0);
9MODULE_PARM_DESC(cs, "SPI chip select (default=0)");
10
11extern struct bus_type spi_bus_type;
12static struct spi_master *master;
13static struct spi_device *spi_device;
14
15static int __init spidev_init(void)
16{
17 char *spi_name;
18 struct device *dev;
19
20 master = spi_busnum_to_master(busnum);
21 if (!master)
22 return -ENODEV;
23
24 spi_name = kzalloc(strlen(dev_name(&master->dev)) + 8, GFP_KERNEL);
25 if (!spi_name)
26 return -ENOMEM;
27
28 snprintf(spi_name, strlen(dev_name(&master->dev)) + 8,
29 "%s.%u", dev_name(&master->dev), cs);
30 dev = bus_find_device_by_name(&spi_bus_type, NULL, spi_name);
31 kfree(spi_name);
32 if (!dev)
33 return -ENODEV;
34
35 spi_device = to_spi_device(dev);
36 put_device(dev);
37 if (!spi_device)
38 return -ENODEV;
39
40 return 0;
41}
42
43static int spi_dev_write(void *buf, unsigned long len, int buswidth)
44{
45 struct spi_transfer t = {
46 .speed_hz = 2000000,
47 .tx_buf = buf,
48 .len = len,
49 };
50 struct spi_message m;
51
52 if (!spi_device)
53 return -ENODEV;
54
55 spi_device->mode = SPI_MODE_0;
56 t.bits_per_word = (buswidth == 16) ? 16 : 8;
57
58 spi_message_init(&m);
59 spi_message_add_tail(&t, &m);
60 return spi_sync(spi_device, &m);
61}
62
63static int spi_dev_read(unsigned char devaddr, unsigned char reg_addr,
64 void *buf, size_t len)
65{
66 u8 txbuf[4] = { devaddr, 0, reg_addr, 0 };
67 struct spi_transfer t = {
68 .speed_hz = 2000000,
69 .tx_buf = txbuf,
70 .rx_buf = buf,
71 .len = len,
72 };
73 struct spi_message m;
74
75 if (!spi_device)
76 return -ENODEV;
77
78 spi_device->mode = SPI_MODE_0;
79 /* txbuf and need fromDevice , isExample */
80 spi_message_init(&m);
81 spi_message_add_tail(&t, &m);
82 return spi_sync(spi_device, &m);
83}
6.6. User-Space SPI Read/Write Program Example¶
followingDescriptioninUser Through spidev DeviceNodeand ioctl SPI Read/writeofSteps。CompleteImplementationcanRefer to SDK in tools/spi/spidev_test.c。
Steps 1:EnableDeviceNode
static const char *device = "/dev/spidev1.0";
int fd = open(device, O_RDWR);
if (fd < 0)
/* Error Handling */;
Note
DeviceNodeand SPI ControllerCorrespondence(withActual ls /dev/spidev* is ):
:SPI Controller 0 Defaultis
/dev/spidev1.0,SPI Controller 1 is/dev/spidev2.0,with (Controller N spidev(N+1).0)。IfDisable SPI Controller(IfDisableController 0), afterControllerNode before : SPI Controller 1 is
/dev/spidev1.0,Controller 2 is/dev/spidev2.0,with 。
OperationandController 0 。
Steps 2:Settings SPI Mode
ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode);
if (ret == -1)
/* Error Handling */;
ret = ioctl(fd, SPI_IOC_RD_MODE32, &mode);
mode Value Kernel File include/linux/spi/spi.h,for example:
#define SPI_CPHA 0x01 /* */
#define SPI_CPOL 0x02 /* */
#define SPI_MODE_0 (0|0)
#define SPI_MODE_1 (0|SPI_CPHA)
#define SPI_MODE_2 (SPI_CPOL|0)
#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)
/* Example:mode = SPI_MODE_3 | SPI_LSB_FIRST; */
Steps 3:Settings (bits per word)
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1)
/* Error Handling */;
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
Steps 4:Settings Rate
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1)
/* Error Handling */;
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
speed not 25MHz, withfromDevice is 。
Steps 5: / Data
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1)
/* Error Handling */;
tr is struct spi_ioc_transfer Address, Description of and 。
CompletecanRunExample
willon Steps ,and on File、struct spi_ioc_transfer of and , can tocan BuildRunofProgram(needKernelProvide /dev/spidev* and File):
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <errno.h>
5#include <fcntl.h>
6#include <unistd.h>
7#include <sys/ioctl.h>
8#include <linux/spi/spidev.h>
9
10#define SPI_DEV "/dev/spidev1.0"
11#define SPI_SPEED 10000000
12#define SPI_BITS 8
13
14int main(void)
15{
16 int fd;
17 int ret;
18 __u8 mode = SPI_MODE_0;
19 __u8 bits = SPI_BITS;
20 __u32 speed = SPI_SPEED;
21 __u8 tx_buf[4] = { 0x01, 0x02, 0x03, 0x04 };
22 __u8 rx_buf[4] = { 0 };
23
24 struct spi_ioc_transfer tr = {
25 .tx_buf = (unsigned long)tx_buf,
26 .rx_buf = (unsigned long)rx_buf,
27 .len = 4,
28 .speed_hz = speed,
29 .bits_per_word = bits,
30 };
31
32 fd = open(SPI_DEV, O_RDWR);
33 if (fd < 0) {
34 perror("open " SPI_DEV);
35 return EXIT_FAILURE;
36 }
37
38 ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
39 if (ret == -1) {
40 perror("SPI_IOC_WR_MODE");
41 close(fd);
42 return EXIT_FAILURE;
43 }
44
45 ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
46 if (ret == -1) {
47 perror("SPI_IOC_WR_BITS_PER_WORD");
48 close(fd);
49 return EXIT_FAILURE;
50 }
51
52 ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
53 if (ret == -1) {
54 perror("SPI_IOC_WR_MAX_SPEED_HZ");
55 close(fd);
56 return EXIT_FAILURE;
57 }
58
59 ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
60 if (ret < 1) {
61 perror("SPI_IOC_MESSAGE");
62 close(fd);
63 return EXIT_FAILURE;
64 }
65
66 printf("TX: %02x %02x %02x %02x\n", tx_buf[0], tx_buf[1], tx_buf[2], tx_buf[3]);
67 printf("RX: %02x %02x %02x %02x\n", rx_buf[0], rx_buf[1], rx_buf[2], rx_buf[3]);
68
69 close(fd);
70 return EXIT_SUCCESS;
71}
BuildandRun:arm-none-linux-uclibcgnueabihf-gcc -o spidev_demo spidev_demo.c -static,inon the target boardExecute ./spidev_demo。DeviceNodeand SPI ControllerCorrespondence on Note;Rate、Mode、 can fromDevice Modify。