How to read data from a serial (SPI) connection in

2019-03-02 17:24发布

问题:

I am trying to write a program that will be installed on a Linux MCU (Raspberry Pi) that will read serial data coming to it from yet another MCU (something homegrown that I will build myself).

I have researched how to do this and think I have the "big picture" but still missing a few things. For one, I need to enable the kernel module and give myself access to the device:

sudo modprobe spi_bcm2708
sudo chown `id -u`.`id -g` /dev/spidev0.*

From there I can use this famous C file to test the SPI connection.

So now the connection is there, but I still need to read serial data from it. According to the answer to this SO question, I just need to:

...open the relevant port for reading, and use read() to get the data.

However the code snippet in that answer seems to be opening up a port through a device driver, not via SPI.

My understanding was that I could use SPI to read data from the connected MCU device, and that I would not need to write my own device driver for that device. Is this true? If so, how would I read from an SPI connection, and how would that code be different than the code in the answer to the question linked above?

And if my understanding is incorrect, and I do read "through" a device driver, why do I need the driver in the first place? Isn't that what SPI hopes to circumvent? Thanks in advance.

回答1:

I am trying to write a program that will be installed on a Linux MCU (Raspberry Pi) that will read serial data coming to it from yet another MCU (something homegrown that I will build myself).

[MCU is not the proper term to use. The Raspberry Pi uses a SoC (System on a Chip). A microcontroller would be a cheaper & simpler device than a SoC. If you want to use a TLA, then use SBC, single board computer.]

[You are misusing the terms "serial port" and "serial data". Today, because of the ubiquity of PCs, "serial port" has come to exclusively refer to EIA/RS-232 asynchronous serial connections. SPI. USB. I2C, TWI, SATA et cetera should not be referred to as "serial" connections unless you are explaining how they work.]

In Linux the SPI device driver is often implemented as a *platform driver" rather than a character driver. Therefore such a driver would not have file operations, or fops, to perform open(), read(), write() or close(). Such operation are for target devices, which the platform device connects to the system. As a consequence, platform devices do not have device nodes in /dev like target devices do. SPI is in the same category as USB and PCI; they are all buses and typically implemented as platform drivers.

My understanding was that I could use SPI to read data from the connected MCU device, and that I would not need to write my own device driver for that device. Is this true?

The answer depends on whether the kernel you use has a SPI char device exposed for your user program to use. But if the SPI driver is a platform driver, then a device driver for your custom SBC would have to be implemented. This target device would need a node in /dev, major and minor numbers assigned and a driver associated with those numbers. This driver would utilize the platform operations that the SPI driver provides or use the Linux SPI API to perform the transfers. The SPI and its driver are merely conduits for transferring data between this processor and the target device. LIke SATA and PCI, the user is rarely aware of these (internal) buses that connect peripheral devices to the computer.

linux/drivers/spi/spi_bcm2708.c is a platform driver. It has no fops to support/perform open(), read(), write() or close() operations. It registers itself as a SPI master, so other (target) drivers can use the SPI API for its services.

IMO you would be better off implementing an EIA/RS-232 link between the RPI and your custom SBC. If non-canonical (raw) transfers were used, then probably 99% of the code you write will be reusable if/when you convert/upgrade to a SPI connection. A 3-wire serial connection with no flow control is similar to a SPI connection, but with no master/slave hierarchy imposed, a simpler HW interface, and longer possible cable lengths.

Beware that you may not be able to achieve fast transmission rates with long SPI distances using whatever cable you rig up. The 10s of Mbps rates for SPI are typically achieved on multilayer boards with ground planes and short traces.



回答2:

On Unix everything is a file

If the spi_bcm2708 driver installed correctly there should be a /dev/whatever file for the device ( or several for accessing the device in different ways).

If one wasn't created automatically you can make an entry with mknod

User space code simply has to open the /dev/whatever file as if it was any other regular file and read/write data from it. That's the whole point of Unix.

edit: that's exactly what the code in the linked question is doing, it's opening the terminal /dev/ttyS0 as a file with open() and reading/writing to it.



回答3:

Have you find Linux documentation of SPI ?

There are couple good documents: spi-summary and spidev.

There is also example in file spidev_fdx.c, where read() is used for SPI device.

But usually reading from SPI is handled by ioctl() function.