SPI low level driver

I’m writing a SPI driver for the PRU on BBB.

Mux settings for pins is done by config-pin: P9.29, P9.30 and P9.31 are configured as “spi” for SPI1_D0, SPI1_D1 and SPI1_SCLK, while P8.27, P8.29 and P9.28 are configured as gpio output as 3 chip select (to be manually managed).

Chip select pin are ok but I can’t transmit/receive anything by the spi.

  1. The PRU code checks register CM_PER_SPI1_CLKCTRL to verify if the module is enabled (interface and functional clocks provided to).

  2. in case it enable the module and wait for fully functional status.

  3. Then MCSPI_SYSCONFIG register is set to 0x030A (clocks always present, idle requests rejected, no autoidle plus module soft reset).

  4. The initialization continues only when register MCSPI_SYSSTATUS confirm that reset is completed.

  5. follows the setting of:

MCSPI_MODULCTRL to 0x0003 (no delay before first tx, functional mode, master, SPIEN not used, SINGLE mode)

MCSPI_CH0CONF to 0x200107BC (1clk clock granularity, FIFOs non enabled, no turbo mode, Tx on SPI1_D1, Rx on SPI1_D0, 16bit word, CLKD=15, mode0)

MCSPI_CH0CTRL to 0x1E01 (EXTCLK=30, channel 0 enabled)

Initialization is done.
With EXTCLK and CLKD settings I’m expecting a 100kHz spi clock (48MHz/(CLKD + 1 + EXTCLK*16)=100kHz)

But when I write to register MCSPI_TX0, there’s no activity at all on the spi pins, while I’m expecting the transmission/reception starts just after the writing into TX0 register…

Reading MCSPI_CH0STAT give me 0x00: EOT=0 (shift register sill loaded with data), TXS=0 (TX0 register full), RXS=0 (RX0 register empty).

Am I missing something?


Are you reading back all the registers to make sure all your writes work OK?

Have you tried enabling the mux on one of the CS signals? I don't have
any real reason to believe it is necessary, but I'd want you to try in
as normal a mode as possible to get things working before tweaking.

Have you tried out Starterware and the Starterware steps to try to
generate a known-good configuration from the PRU?

Hello Jason, thanks for advices.

I’ve done the first and I’ve found a bug: just after soft resetting the module I have to rewrite register MCSPI_SYSCONFIG (to 0x0308) 'cause the module also resets this register…
The others settings seems ok.
SPI trasmission still doesn’t occours, so there must be something else.

I’ll try the other 2 suggestions.

I did some work on this in January. I am not sure it worked well, at least it did something.
The code (so far) may help: https://github.com/kkwekkeboom/am335x_pru_package/blob/csk_spidriver2/pru_sw/example_apps/PRU_spidriver/PRU_spidriver.p


Hello Kees,

something is always better than… nothing :wink:
That’s was exactly what I was looking for: a “working” driver for compare initialization sequence and register settings.

My init was very similar… but I noticed you deal also with interrupt registers and that you used the “FORCE” option in CH0CONF.
This last one is the turnkey: simply adding the FORCE flag setting to my sequence, the SPI start workings properly, transmitting and receiving data as expected.

Many thanks!

Hello Gianfranco,

Happy to help you out. I think instead of using the ‘force’ bit, there must be a better alternative, but this solution works.
Did you start working on SPI in the PRU because the linux mcspi driver is very slow?


Hi Kees,

SPI management is part of a bigger project: we are working on a Machinekit based drilling machine, where one PRU is used for the generation of step/dir signals for the axes, while the other already manages (in real-time way, tightened to the main servo-thread @ 1 ms) an I2C bus (for I/O expanders, ADCs, DACs, RTC…), 2 CAN buses (for a custom board with 5 servo brushless and future remote I/Os) and now… SPI bus (to interface 2 additional step drivers).

We tryed at first with the linux driver (as we really don’t need strict real-time management for that) but we had some troubles integrating it into the Machinekit enviroment. Speed was only one of the problems…
Anyway, now it’s all into the PRU and it’s working very well.