Enabling real-time mode for Linux SPI driver - linux

I have an application that uses an ARM device running Debian Stretch (soon to be Bullseye) that is using SPI for high speed point-to-point communications to another device. I am using the spidev driver. I am seeing a lot of latency in each transaction, taking up to 700 microseconds for a burst of 256 bytes at 10MHZ. I have to transfer this burst every 1 millisecond.
I want to test reducing the latency in the Linux SPI driver. I see that struct spi_device has some fields to control that:
From spi.h
#rt: Make the pump thread real time priority.
#cs_setup: delay to be introduced by the controller after CS is asserted
#cs_hold: delay to be introduced by the controller before CS is deasserted
How do I set these?
I've done a lot of searching about this but I can't find the connection between setting struct spi_device and any external mechanism.

Related

What is the relationship between SPI and DMA in linux?

In my opinion, SPI and DMA are both controllers.
SPI is a communication tool and DMA can transfer data without CPU.
The system API such as spi_sync() or spi_async(), are controlled by the CPU.
So what is the meaning of SPI with DMA, does it mean DMA can control the SPI API without CPU? Or the SPI control uses CPU but the data transfer to DMA directly?
SPI is not a tool, it is a communication protocol. Typical micro controllers have that protocol implemented in hardware which can accessed by read/write to dedicated registers in the address space of the given controller.
DMA on micro controllers is typically designed to move content of registers to memory and visa versa. DMA can sometimes configured to write a special amount of read/writes or increasing or decreasing source and target address of memory and so on.
If you have a micro controller which have SPI with DMA support, it typically means that you can have some data in the memory which will be transferred to the SPI unit to send multiple data bytes without intervention of the cpu core itself. Or read an amount of data bytes from SPI to memory automatically without wasting cpu core.
How such DMA SPI transfers are configured is written in the data sheets of the controllers. There are a very wide span of types so no specific information can be given here without knowing the micro type.
The linux APIs for dealing with SPI are abstracting the access of DMA and SPI by using the micro controller specific implementations in the drivers.
It is quite unclear if you want to use the API to access your SPI or you want to implement a device driver to make the linux API working on your specific controller.
It is not possible to give you a general introduction to write a kernel driver here or clarify register by register from your data sheets. If you need further information you have to make your question much more specific!

How to send data to AXI-Stream in Zynq from software tool?

I'm looking for a way to send some data from my software app written in C to AXI-Stream interface of Zynq. Something like
open(/dev/axistream);
send_data(data);
I'm running Linux on the Arm part and now I want to connect it to the programmable logic part.
On a zynq device communication between the Cortex-A9 processor and FPGA is done using AXI protocol. There are three types of ports which can be used to communicate between FPGA and CPU (Zynq TRM) :
General Purpose AXI ports: 2x Master (from CPU to FPGA) and 2x Slave port (from FPGA to CPU). these ports are connected to the central interconnect of the processing system and can be used to transfer data to/from DDR memory or on-chip memory (OCM).
High Performance AXI ports: 4x Slave port (from FPGA to CPU) provide high-bandwidith access to DDR or OCM
ACP (Accelerator Coherency Port): Slave port (from FPGA to CPU) high-troughput port connected directly to the snoop control unit (SCU). The SCU maintains cache coherency (ommits the need for cache flush/invalidates).
From your question, I would understand that in your case the CPU is the Master of the communication. You will need to use the General-Purpose axi master ports. You cannot connect an AXI4 streaming interface to the AXI interconnect. You will need to convert AXI4 Streaming to AXI. Depending on your performance needs an AXI DMA ip core (AXI DMA IP core) might be a good solution.
If you want to communicate from software point of view using "open(/dev/)" you will need a Linux device driver. If you are using the DMA core your communication will typically look like this:
You will configure the DMA core to fetch data from a certain memory address
Start the DMA core
the DMA core will fetch the data and feed it to the AXI4 streaming interface of your IP block
Your IP block will do some operation on the data and send back to memory (using DMA) or do something else (send to external interface, ...)
The register set of your DMA core will be memory mapped and accessible through you own linux device driver. For debugging purposes i would suggest using mmap to access the registers and quickly validate the operations of your hardware. Once you go for the linux kernel device driver i would suggest you reading this book: Linux Device Drivers 3the edition
The best choice for efficient data transfer is using DMA enabled PS-PL communication. After implementing a DMA controller inside PL, such as AXI CDMA you can connect it to an AXI4-Stream IP then to your desired IP core.
If your not going to set up a general framework you can access DMA-enabled part of DDR memory using mmap() system call.
Here is a template to transfer data from user space to the IP core in which a loop-back is implemented.
https://github.com/h-nasiri/Zynq-Linux-DMA
Zynq AXI CDMA
The AXI CDMA uses processing system HP slave port to get read/write access of DDR system memory. There is also a Linux OS based application software that uses mmap() to initialize the DMA core and then do the data transfer.
You can easily add an AXI4-Stream interconnect to the AXI CDMA and connect
If I understand correctly, you want to DMA data from the from the PS to PL using the DMA engine. In that case, you would need to write a driver in Linux which will either use the AXI DMA engine driver, or configure the DMA engine from user space.
Is that what you are looking for?

servicing interrupts in SPI

I am working on a project in embedded Linux with beagle bone to transfer 300 bytes of data as one block in one write cycle to a slave (Atmel uC). After having read the Documentation on Spi ie /Documentation/spi I have found that the DMA gets enabled when the data transfer threshold exceeds 160 bytes as mentioned in /drivers/spi/omap2_mcspi.c
I would like to enable flow control based on exchange of const 4 byte values between my beaglebone and Atmel uC. Once I have sent a command say CMD_DATA, the slave responds with RC_RDY. I would like to make a kernel module that services interrupts and calls an interrupt handler every time upon receiving data from slave so that I can check for this ack from slave.
How do I enable interrupts and register interrupt handler for SPI? Any sample codes or tutorials would be helpful. I have looked extensively online and all I found was setting up interrupts for GPIO's
Thanks!

How to get the interrupt time (timestamp) in kernel mode of real time Linux?

Client/server communication - client is sender and server is receiver.
When the server receives the data on the ethernet interface(UDP) the kernel in the server is triggered. I am using real time LINUX on the server side. Server (i.e. embedded pc target) is handling interrupts to trigger the embedded pc target (containing rt Linux) to gain the attention to execute the newly arrived data.
How can I calculate the time in kernel as soon as the interrupt occurs and send the response back to the client?
1) If you are using an embedded linux platform, you can refer to CPU datasheet: maybe it have a set of high-speed timers. At instance, I'm using SoC based on ARM Cortex A8, it has GP timers that can be clocked up to 38.4 MHz, so I can measure execution time with ~27ns precision. Very likely, your OS would not provide such API, so you're welcome to read-write CPU registers directly from kernel driver.
2) If you are want to just estimate execution time, and nothing more, you can use one of GPIO pins of your board. Set pin up at "start", set down at "end", then watch this pin by oscilloscope, if you have one.
3) If I missunderstood you, and all that you need is timestamp of a real time (like HH:mm:ss), you can refer to RTC chip of your board. Using driver of real-time clock chip, you can read time from your kernel module. Unfortunately, you might not be able do it from interrupt service routine.
Or just call do_gettimeofday and convert timeval to something human-readable via time_to_tm, if needed :)

Best way to transfer video data to a device over PCI in linux

I need to transfer video data to and from an FPGA device over PCI in a linux environment. I'm using a third party PCI master core on the FPGA. So far, I've implemented a simple DMA controller on the FPGA to transfer data from the FPGA to the CPU, using consecutive PCI write bursts.
Next, I need to transfer video data from the CPU to the FPGA. What is the best way to go about this?
Should I implement a module on the FPGA which performs a whole bunch of burst reads over PCI. Or is there a way to get the CPU to efficiently write data into the FPGA's memory using PCI write bursts?
My bandwidth requirements are around 30 MB/s in both directions.
Thanks.
You could do posted writes from CPU like what video card drivers do but you'll need to have some driver magic such as setting MTRR (which means you might have some architectural dependency). If you want to be safe DMA read from FPGA is a better way to go. 30MB/s isn't much.
Sounds to me the FPGA should master both reads and writes. Otherwise you would hog the host CPU. That's a classic task for a DMA (and you cannot guarantee a DMA exists on every host).

Resources