SPI: Linux driver model - linux

I'm new with SPI; the Linux kernel provides an API for declaring SPI busses and devices, and managing them according to the standard Linux driver model.
You can find the description of the struct spi_master here: https://www.kernel.org/doc/htmldocs/device-drivers/API-struct-spi-master.html
The description at the link above says that "Each device may be configured to use a different clock rate, since those shared signals are ignored unless the chip is selected". To put the sentence in a contest, I have to say that with "device" they mean SPI slave device, and with "those shared signals" they mean MOSI, MISO and SCK signals.
In fact, in the struct spi_device (https://www.kernel.org/doc/htmldocs/device-drivers/API-struct-spi-device.html) there is an attribute named max_speed_hz that is not present in the struct spi_master. So I can understand on the first part of the statement above: "Each device may be configured to use a different clock rate".
But, what does mean the second part? Does "since those shared signals are ignored unless the chip is selected" mean that I'm allowed to used different clock rates but only one at time by enabling/disabling the slaves with different rates?
Thank you for your help! Regards,
--
Matteo

#Matteo M.: I think you actually are not allowed to simultaeously setting SS1, SS2 and SS3 to zero and in this way enabling all three SPI slaves at the same moment in time. The reason is, that the SPI slaves, while receiving data on the MOSI line, simultaneosly send back data on the MISO line. If actually all three slaves would put data on the (shared) MOSI line, really bad things could happen, both regarding the data and the electrical flow.

SPI is a very loose "standard", there are not many rules to follow, which is good (and bad I guess). It is good because it is flexible. It is bad because it can be implemented differently depending on the specific hardware you are dealing with. Some devices support only half-duplex communication, which as you know requires coordination of when the bus can be driven. Select lines (chip enable, slave select, whatever you want to call them) provide a handy way to do this without using bits to identify which slave should get a message off the bus.
In the full-duplex mode, where data is dropped onto the bus from the master and from the slave on each clock pulse, the select line could be very much required to prevent bad things, as Wolfgang stated. I want to stress could be required; it is completely reasonable to have perhaps a master processor communicating with other processors that only drive the bus when responding to some specific bit pattern (like for instance, an "address")... More software/firmware? Yeah, but it is not stopping you.
So, if your 8-bit slaves are say, for instance 8-bit DACs you could indeed write the values chunks of the master data register. Independant select lines will enable you to do this without all those slaves driving the bus at once. Yeah, you have to shift the values from each slave into the master register one at a time, but that too is a completely reasonable design.
Unlike some more complex serial protocols SPI is actually really flexible; because it doesn't lock you into max word size or require any of the data you write to the bus to be comprised of things like addresses and offsets and stuff.

Related

Raspberry Pi program that interfaces with I/O (HID, SPI, GPIO)

I am working on a project using a Raspberry Pi where I need to create a GUI that can interface with the various peripherals. Specifically the program needs to:
-read the position data from a touchscreen, mouse, or other HID
-perform some math on on the position data
-store the data in a FIFO buffer
-output that data over the SPI port at a fixed frame rate
I have an electronics background, with some experience writing firmware for microcontrollers, but I'm a relative novice when it comes to this kind of stuff. I have done some research, and it looks like the mouse/touchcreen data is available by reading a file in the /dev/input directory, and I assume you can access the SPI port by reading or writing to some file in the /dev directory. (I am currently running Raspbian)
My initial thoughts were to write a simple C program that a) reads the touchscreen data file and stores it into a preallocated buffer in memory and b) writes the data that next in line to the SPI data file in order to write it out to the SPI port. Part (a) would fire off either on a timer interrupt and poll the touchcreen data to see if it's new, or fire off from a "new data" interrupt. Part (b), the SPI part of the program, would fire off at a fixed rate, probably from a timer interrupt.
So my questions are:
-Is it even possible (or easy) to access interrupts or system timers from the user space? I assume you would need to get hooks into the kernel somehow?
-If so, how would I make it so that my function runs whenever a interrupt or timer fires off?
-How easy is it to use the SPI DMA in user space? Does anyone have any experience doing that? I did a little research and it looks like you need to load a custom kernel driver, but I didn't know how tricky that would be.
-Is it possible to write out a parallel word on the GPIOs the way you would do it on a microcontroller (ie all at once by writing the word to the port's output register)?
I know there are plenty of higher level programming languages and wrappers that allow you to talk to the perepherals, but I'm a little hesitant doing it that way since the timing seems pretty tight. I need to output (3) 16-bit words per frame at ~1k frames per second. At 500kHz SPI bitrate, each frame is 96 us long, and at 1k frames per second, each period is 1ms. This is why SPI DMA, or even writing the data out as a parallel word would be a lot easier in terms of timing.
Thanks for the help!

Using two USART ports on the STM32-Discovery

I am using an STM32-Discovery board for my first time. I want to use two of the USART ports on the board at the same time to read in serial information. Can the STM32 read in serial information from both of these USART ports at the same time? Do I need to set an interrupt instead, to switch between them?
I realize this is connected to threading on the board, but I do not understand the threading of the board.
You can read and write as many peripherals as you wish. But of course you need to do it a proper way. For example if you poll for the data from UART1 the data can be overrun on the another ones. So you need to implement other methods like using the interrupts. The topic is too broad for the simple answer.

PCIe device discovery algorithm pseudo code

I have a PCIe model written in System Verilog, although I think this question is language agnostic. The model performs PCIe configuration reads and writes and memory reads and writes perfectly in simulation. However, what I need to do is "discover" my PCIe device and configure my config space registers in simulation. Is there a boiler plate chunk of pseudo code that represents the Linux PCIe enumeration process that I can just add my own models transactions functions too so that I can get a "Bus walk", followed by BAR programming, SR-IOV enable if discovered, MSIx config? It seems like this would be a common exercise for PCIe device so maybe there is model.
It isn't terribly difficult to do. Basically you loop through the config space, checking for each each possible device on the first root bus 0. When a device is found, you allocate a memory space for it based on its requested size and program the BARs accordingly. If you find any bridges, you also configure and enable them - the basic bridge registers for this are standard. This includes assigning the upstream and downstream bus numbers, which then allows you to enumerate the new downstream bus, and so on.
I had to do this once to access a PCI I/O card on a system that had no OS or other software environment. It wasn't too bad and that was across two bridges from two vendors, as well as the I/O card registers and the CPU bus root bridge setup. This was PCI, not PCIe, but it would be very much the same. You could even do it with completely hard-coded numbers if the hardware never changed, but in my case there were a couple variants so I actually had to do some simple enumeration to find the device numbers dynamically. One gotcha is that you may have to delay a bit, or retry, to give all the devices time to come online before you try to access them.
In doing that I found this book to be invaluable: PCI System Architecture (4th Edition). I notice there is also an version for PCIe: PCI Express System Architecture (1st Edition). I would definitely get one of those if you haven't already. These books contain detailed algorithms and explanations about how to do all of this. At the time I didn't really use or refer to any code to speak of, but...
The best code resource I have found is U-Boot. It operates at a similarly low-level and is totally self contained and is still fairly small and as simple as possible. For example, the enumeration appears to start with the function pci_init() calls a board specific pci_xxx_init(). This then sets up the root bridge and then calls pci_hose_scan_bus() in drivers/pci/pci.c to do the real work. Also check out the routines in drivers/pci/pci_auto.c, as well as the rest of the folder.
For your task you probably only need a very small subset and could just hack out parts of these files into a simple driver. Basically a for() loop and some pci_read/write_config() calls with logic to recognize your device and bridge IDs.

How to generate a steady 37kHz GPIO trigger from inside linux kernel?

I have a micro controller taking care of infrared TX-carrier wave generation currently, but I started wondering if I could dispose of it, and do this work in linux side - thus bringing the cost of my embedded system down.
I'm running on a Freescale i.mx233 (454MHz ARM9), and if I access registry directly through /dev/mem, I can achieve quite steady 5MHz triggering to a GPIO pin.
Since I need 37kHz, I started looking ways of slowing it down, but it seems that at least nanowait() is way too rough for this purpose.
I found one solution of calling rand() in a for loop, and I seem to be able to generate 38,4kHz signal quite well, However there is some unacceptable jitter from time to time according to oscilloscope. (I understand that this is quite a bit waste of resources, but when the TX needs to be done, the system has no other tasks really)
My questions:
Freescales kernel code (3.8 branch) doesn't have CONFIG_PREEMPT_RT patches, so that is one thing maybe I should look into, but before that:
Could I achieve more accurate performance, by writing a kernel module to drive the GPIO from inside the kernel ? I do need to read up on some data from user space (data to be sent), but other than that, I only need to trigger the led on specified frequency at the end of the GPIO, so the driver should be pretty simple.
Can I force the priority of my driver, so that other tasks don't interrupt this gpio triggering ? (data sending takes currently roughly 400ms, and it's done very seldom)
Is there some better way to create an interrupt say every 37kHz, so that I don't stall the system by SW ?
Micro controller is perfect for this kind of tasks, but it would be nice to avoid this cost overhead if possible...
The i.MX23 PWM in "Multi-Chip Attachment Mode" is designed exactly for this requirement.
Use one of the PWM's in "Multi-Chip Attachment Mode", for example, assuming you are using a 24Mhz clock, with
MATT=1 (Enable multi-chip attachment mode)
MATT_SEL=1 (User 24Mhz clock)
CDIV=0x2 (or DIV_4, i.e. divide by 4)
INACTIVE_STATE=0x2 or 0x3
ACTIVE_STATE=0x3 or 0x2
PERIOD=175 (i.e 176-1)
If you use a 32Mhz clock you will need other CDIV and PERIOD parameters to get to 34Khz.
See the "i.MX23 Applications Processor Reference Manual" for example code. If I am not mistaken the driver code is in arch/arm/plat-mxc/pwm.c but it doesn't seem to support the MATT mode. You will probably have to extend the code yourself.
Regarding the implementation -
The above answer relates to the CPU only. In practice, the ability to implement the idea depends on the board design. The board would need a header (pins for external connection) that connects to a GPIO pin that can be connected via the pinmux to one of the PWMs. I would assume that most reference designs would have at least one PWM configurable GPIO exposed through a header. The the question is if there is only one and if you are already using it for some other control purpose.
After determining that there is a header with a free PWM configurable GPIO, you need to configure the pin mux and activate the PWM. There are instructions for this in the processor reference manual noted above. Most systems do this configuration in the boot loader board_init() (assuming U-boot), although it can probably be done in userspace also with some mmap trickery after Linux boots.
Finally you would need to write a driver based on the interface to the PWM module in platform-mxc_pwm.c.
If you are using the i.MX23 EVK 10.05 you might be able to modify the LED PWM driver since it is already configured at the level of the bootloader and kernel and connect your device to the LED output instead of the LED. (You will need a hardware technician to help you with this.) Make sure you config the kernel with the CONFIG_LEDS_MXS.
The above comments regarding implementation are somewhat speculative since I don't know the EVK. Perhaps someone who knows it can improve on this.
Update September 21, 2013
Another way to generate a 37kHz signal with the i.MX23 or with any SoC with a similar ARM CPU core is to use an unused on-chip timer to generate a FIQ interrupt at the required frequency and write a FIQ interrupt handler to toggle a GPIO pin. Maxime Ripard posted a complete example of this method using the i.MX28 SoC on his Free Electrons blog on April 30 this year. To use this method you will need both an unused timer and not be using the FIQ interrupt for another purpose such as one of the SPI, camera, or brownout-detection drivers that use the ARM FIQ. You will also need to write the ISR in ARM assembler.
The best way to get a 37 kHz signal would be to find some serial/audio/PWM output that can generate it in hardware.
It might be possible to raise the priority of your userspace process, but this won't help against interrupts or high-priority kernel tasks.
An RT kernel would allow you to get priority over more kernel tasks, but wouldn't help against all interrupts.
I don't know if you will be able to get the maximum latency below 37 kHz (27 µs); I think it's unlikely.
Doing this in the kernel would help because you could disable interrupt handling.
However, disabling interrupts for as long as 400 ms is frowned upon.

Is forcing I2C communication safe?

For a project I'm working on I have to talk to a multi-function chip via I2C. I can do this from linux user-space via the I2C /dev/i2c-1 interface.
However, It seems that a driver is talking to the same chip at the same time. This results in my I2C_SLAVE accesses to fail with An errno-value of EBUSY. Well - I can override this via the ioctl I2C_SLAVE_FORCE. I tried it, and it works. My commands reach the chip.
Question: Is it safe to do this? I know for sure that the address-ranges that I write are never accessed by any kernel-driver. However, I am not sure if forcing I2C communication that way may confuse some internal state-machine or so.(I'm not that into I2C, I just use it...)
For reference, the hardware facts:
OS: Linux
Architecture: TI OMAP3 3530
I2C-Chip: TWL4030 (does power, audio, usb and lots of other things..)
I don't know that particular chip, but often you have commands that require a sequence of writes, first to one address to set a certain mode, then you read or write another address -- where the function of the second address changes based on what you wrote to the first one. So if the driver is in the middle of one of those operations, and you interrupt it (or vice versa), you have a race condition that will be difficult to debug. For a reliable solution, you better communicate through the chip's driver...
I mostly agree with #Wim. But I would like to add that this can definitely cause irreversible problems, or destruction, depending on the device.
I know of a Gyroscope (L3GD20) that requires that you don't write to certain locations. The way that the chip is setup, these locations contain manufacturer's settings which determine how the device functions and performs.
This may seem like an easy problem to avoid, but if you think about how I2C works, all of the bytes are passed one bit at a time. If you interrupt in the middle of the transmission of another byte, results can not only be truly unpredictable, but they can also increase the risk of permanent damage exponentially. This is, of course, entirely up to the chip on how to handle the problem.
Since microcontrollers tend to operate at speeds much faster than the bus speeds allowed on I2C, and since the bus speeds themselves are dynamic based on the speeds at which devices process the information, the best bet is to insert pauses or loops between transmissions that wait for things to finish. If you have to, you can even insert a timeout. If these pauses aren't working, then something is wrong with the implementation.

Resources