SPI slave controller fails to transact buffer contents (TXFLR & RXFLR constant)

Hi!

SYNOPSIS: I'm having issues trying to run the Arduino 101's SPI slave controller: it appears as if there is no external signal or the SPI controller is ignoring it, even though the signal is present and the SPI controller appears to be configured properly.

I'm trying to test a SPI master device by running an Arduino 101 in SPI slave mode, so that I can programmatically compare the master's behavior to the expected behavior.

As I understand it, the current SPI library doesn't contain code for controlling the slave SPI controller, so I hacked together some code myself, which I've attached.

For quick reference, here's the main chunk of code that I'm using to configure the SPI controller:

#define SPI_S_REG_VAL(reg) MMIO_REG_VAL_FROM_BASE(SOC_SLV_SPI_REGISTER_BASE, (reg))

  noInterrupts();

  SPI_S_REG_VAL(SSIENR) &= ~1; // disable
  MMIO_REG_VAL(PERIPH_CLK_GATE_CTRL) |= 0x10000; // enable clock for SPI slave (bit 16)
  SPI_S_REG_VAL(CTRL0) = ((8 - 1) << 16) | (0x03 << 6); // 8 bit frame size; SPI MODE 3
  SPI_S_REG_VAL(IMR) = 0; // no interrupts
  SPI_S_REG_VAL(SSIENR) |= 1; // enable

  interrupts();

  SPI_S_REG_VAL(DR) = 0xD8; // write some sample data to the tx buffer

This code appears to work, but then the transmit data never leaves the buffer, and no receive data ever enters the buffer. (I can tell this by looking at the RXFLR and TXFLR registers on the SPI controller, which stay at 0 and 1, respectively.)

Part of the problem is that there doesn't appear to be a datasheet available for the Quark SE Microcontroller, which is the component of the Curie that appears to contains the SPI slave controller. Instead, I've been using the datasheet for the Quark D2000 Microcontroller, which appears to have the same SPI configuration but just one fewer SPI master port. Since the core libraries include the register offsets (and similar constants) for some of what I'm trying to use, and those numbers match the Quark D2000 datasheet, I don't think that the issue is with the documentation that I'm using.

Since I'm running the SPI controller in Slave mode, I have the SPI master that I'm testing hooked up, and I've used a logic analyzer to verify that the correct signals are being sent, so I'm pretty sure that the slave controller is receiving the correct outside signals. I also ran a sketch that just attached an interrupt to the SPI SCK line and verified that the pin is working properly and receiving what I expect it to be receiving.

The SPI master is running at 2 MHz, which is below the Quark D2000 MCU's 3.2 MHz SPI speed limit. I've verified that I have the same SPI mode (mode 3) on both sides of the connection, and am using the same number of data bits (8 bits).

I've made sure that I've tied SS (slave select) to GND, though I've also tried it with 3.3v and had no luck with that either. I've tried configuring the PIN muxes both via setting pinMode to INPUT on all four lines (MOSI, MISO, SCK, SS) and configuring the PIN muxes by using SET_PIN_MODE to SPI_MUX_MODE (which is what the SPI master does).

For reference, here are the register values reported every 1000 ms in my example SPI slave sketch:

REG 0 = 700C0 (CTRL0)
REG 4 = 0 (CTRL1)
REG 8 = 1 (SSIENR)
REG C = 0 (MWCR)
REG 10 = 0 (SER)
REG 14 = 0 (BAUDR)
REG 18 = 0 (TXFTLR)
REG 1C = 0 (RXFTLR)
REG 20 = 1 (TXFLR)
REG 24 = 0 (RXFLR)
REG 28 = 2 (SR)
REG 2C = 0 (IMR)
REG 30 = 0 (ISR)
REG 34 = 0 (RISR)
REG 38 = 0 (TXOICR)
REG 3C = 0 (RXOICR)
REG 40 = 0 (RXUICR)
REG 44 = 0 (MSTICR)
REG 48 = 0 (ICR)
REG 4C = 0 (DMACR)
REG 50 = 0 (DMATDLR)
REG 54 = 0 (DMARDLR)
REG 58 = 0 (IDR)
REG 5C = 3332332A (SSI_COMP_VERSION)

These register values match what I would expect (what the Quark D2000 MCU documentation documents) for a SPI slave controller with one byte in its TX buffer and zero bytes in its RX buffer.

It seems that the issue is likely to be a PIN muxing issue or a clock issue. I've tried the different PIN mux configurations that made sense to me, as mentioned earlier. In terms of the clock, I used the same configuration that the SPI master driver uses, except with setting bit 16 instead of bit 14. Bit 16 was as specified by the Quark D2000 MCU manual, which also specified the same meaning for bit 14 as appears to be the case for the Quark SE MCU. Just in case the manual was wrong, I also tried setting this to 0xFFFFFFFF (all bits on), so that everything would be enabled. Again, no dice.

I'm also pretty sure that I'm using the correct pins (13 for SCK, 11 for MOSI, 10 for SS, 12 for MISO but currently disconnected because it's a one-way SPI transfer) as the schematic for the Arduino 101 board appears to have the ATP_SPI_S_* pins connected to the IO10-IO13 pins in the same way as the SPI1_M_* pins are.

I would just bitbang an SPI slave, but AFAICT the delays on setting output pins mean that it's not possible to bitbang any sort of serial-like interface at speeds over around ~100 KHz, much less 2 MHz. (That was my result when trying to bitbang half-duplex serial on the Arduino 101, and I don't believe that SPI would be significantly more efficient to bitbang.)

Any ideas as to what I might be doing wrong in my control code for the SPI slave controller? This doesn't appear to be a common usecase, and I haven't been able to find anything for the Arduino 101. (There's SPI slave code available for other variants of the Arduino, but those have different SPI controller registers.)

[This post has been cross-posted to the Intel forums.]

spi_slave_sketch.ino (1.55 KB)

There are two SPI controllers in the Curie. One is attached to the X86 processor in the Quark and the other is attached to the ARC DSP. I think you can only use the ARC SPI from Arduino. Are you sure you are using the correct SPI controller?

RussBarr:
There are two SPI controllers in the Curie. One is attached to the X86 processor in the Quark and the other is attached to the ARC DSP. I think you can only use the ARC SPI from Arduino. Are you sure you are using the correct SPI controller?

I believe that there are five SPI controllers, if I remember the documentation correctly. I think there are three (2x master and 1x slave) on the Quark, and two (1x master and 1x slave) on the ARC. The Arduino code is capable of interacting with the two SPI masters on the Quark through memory-mapped IO registers - this is done in the standard library - and I don't see why it wouldn't also be able to interact with the SPI slave on the Quark.

One of our backup plans, if we can't get the SPI slave controller on the Quark to work, is to try the SPI slave controller on the ARC.

Thanks for the clarification. I am also interested in using the Arduino 101 at a system level and I am having problems running the 6 DOF motion I2C in a timer ISR when I run a serial port in the main loop at the same time. You can see my post and source in this forum as problems running Madwick in an ISR.

I am having problems finding detailed information about the Intel Curio chip. If you have any documentation you can share I would appreciate it. Without the detailed documentation I am only guessing about your problem but there is also an IO pin multiplexing that may need to be setup to connect the SPI you are using.

Thanks
Russ Barr

In your setup you have defined all 4 pins as inputs. In slave mode MISO should be defined as an output. If you are only sending data to the slave this should not matter. You should still be able to receive data at the master. in order to receive data all you need is SS low and eight clock on SCLK at that point you should have an indication on the slave SPI of data received even if MOSI is not connected. If you are not seeing this you are mapped into a SPI that is not connected to I/O pins.

I see that you are trying to send data from the slave since you load the transmit register

SPI_S_REG_VAL(DR) = 0xD8; // write some sample data to the tx buffer

This data can not be sent since MISO is defined as an input instead of an output.
Also since this is a slave SPI the data will not be transmitted by loading the DR register. This data is only held there until the Master SPI selects the slave by lowering SS and the master must send data to the slave in order to generate the 8 clock cycles that will cause the data in the slave SPI to be transmitted to the master.

RussBarr:
I am having problems finding detailed information about the Intel Curio chip. If you have any documentation you can share I would appreciate it. Without the detailed documentation I am only guessing about your problem but there is also an IO pin multiplexing that may need to be setup to connect the SPI you are using.

You can look at the Quark D2000 documentation, which is publicly available. The Quark SE documentation is not, but I've heard that the differences are minimal. And yes, I've tried the obvious options for pin multiplexing, as I talked about in my original post.

RussBarr:
In your setup you have defined all 4 pins as inputs. In slave mode MISO should be defined as an output. If you are only sending data to the slave this should not matter. You should still be able to receive data at the master. in order to receive data all you need is SS low and eight clock on SCLK at that point you should have an indication on the slave SPI of data received even if MOSI is not connected. If you are not seeing this you are mapped into a SPI that is not connected to I/O pins.

The slave isn't actually sending any data anywhere, as I mentioned in the original post. The wire isn't hooked up, and that's purposeful. And yes, I've tried all of that - I'm not new to SPI.

RussBarr:
I see that you are trying to send data from the slave since you load the transmit register

SPI_S_REG_VAL(DR) = 0xD8; // write some sample data to the tx buffer

This data can not be sent since MISO is defined as an input instead of an output.
Also since this is a slave SPI the data will not be transmitted by loading the DR register. This data is only held there until the Master SPI selects the slave by lowering SS and the master must send data to the slave in order to generate the 8 clock cycles that will cause the data in the slave SPI to be transmitted to the master.

Regardless of the MUX settings, the SPI slave device should still attempt to transmit the data in its FIFO, even if the signal goes nowhere. The only reason that I put data into this buffer is so that, while I'm debugging, I can tell when it thinks enough bits have been clocked by the master for it to send or receive a byte. And yes, I am very well aware of how SPI works.

At this point, I'm waiting for Intel to reply to my thread in the Intel forums (the one I linked earlier) - I doubt that this is going to be fixed without documentation or inside information that neither of us have access to.

Your statement

"Regardless of the MUX settings, the SPI slave device should still attempt to transmit the data in its FIFO, even if the signal goes nowhere."

Is not correct. If the MUX settings are not set correctly set the Master SPI clock will not be received by the slave SPI controller even if you can generate a GPIO interrupt on that pin and the data will not be clocked out of the slave SPI controller.

RussBarr:
Your statement

"Regardless of the MUX settings, the SPI slave device should still attempt to transmit the data in its FIFO, even if the signal goes nowhere."

Is not correct. If the MUX settings are not set correctly set the Master SPI clock will not be received by the slave SPI controller even if you can generate a GPIO interrupt on that pin and the data will not be clocked out of the slave SPI controller.

The context for that sentence was this sentence from your earlier post: "This data can not be sent since MISO is defined as an input instead of an output." I was saying that the MUX settings of the MISO pin do not affect the ability of the slave controller to attempt to transmit. I am well aware that the MUX settings matter for the pins that I'm actually using. As I talked about earlier, I tried multiple configurations, including the different available MUX configurations for the clock pin. The point being: the issue is probably not the MUX settings, unless I'm missing a major part in how the configuration is done (such as a undocumented MUX mode or configuring the wrong MUX).

I understand how SPI, SPI slave controllers, and pin MUXes work in general - the parts I'm unfamiliar with are the implementation details of these specific to the Curie.

Only trying to help

I just received some info from Intel about the Curie.

We’re currently working on finalizing our documents and hope to have them available soon. The documentation available is here Self-Help Resources for Maker & Innovator Products, also, in the Intel Curie community (https://communities.intel.com/community/tech/intel-curie/) you can find information helpful and we post our updates there.

You can find the data sheet pdf here www.mouser.com/pdfdocs/Curie_Datasheet_Rev10.pdf

I don't think this will help answer all the questions but it does state what pins are use for the slave SPI.

You probably already know this.

After looking at the new Intel info I have the following info

The SOC SPI1 Master is at Base address 0x0B0001400 and is PIN for PIN connected to SOC SPI SLAVE at base address 0x0B0001800.

I believe you can set up the master and receive it on the slave. Both use CS0 of the corresponding interface.

You need to reverse the direction on the slave from the master pins.

You can easily see all of the SPI signals on the 6 PIN header on the ARDUINO 101.

ARC (DSP) SPI0 is not connected on the 101 board base address 80010000h
ARC (DSP) SPI1 is internal connected to the SENSOR Chip base address 80010100h

SOC Master SPI0 is connected to SPI FLASH on 101 base address B0001000h
SOC Master SPI1 is connected to 6 pin header on the 101 base address B0001400h

SOC Slave SPI is connected to same 6 pin header on 101 base address B0001800h

If you load data in the slave DR register it should be transferred to the master after loading the master DR register.

You should see CS low and clock and SPI1_M_MOSI data on the 6 pin header for the slave to receive.

If you want to use the SLAVE SPI from external you must disable the MASTER SPI1 and tri-state all the signals from the MASTER. You can then drive the SLAVE from an External device through the 6 pin header.

Hope this helps.

One more thing the slave clock is limited to Frequencies up to 3.2 MHz so if you are using the onboard master set it ti 2Mhz or lower.

I don't know if you ever got the SPI Slave port to work but I have been using the INTEL System Studio for Micrcontroller. With a flyswatter2 JTAG debugger.

I think your problem is in the pin multiplexing qm_pmux_select(pin_id, PIN_MUX_FN) and the fact that the SPI1_master is tied to SPI_Slave.

If you are not using the SPI1 as a master to drive the SPI_Slave pins I would recommend making sure they are defined as GPIO inputs by calling qm_pmux_select(PIN_ID, PIN_MUX_FN) with PIN_MUX_FN = PIN_MUX_FN_0 with PIN_ID = 42,43,44, and 45. GPIO 8-11 the four SPI1_M pins.

You will also need to set up the SPI_S pins. These pins need to be configured as PIN_MUX_FN_2 since that is what GPIO 0-3 second function are. The pin numbers for these are 34,35,36, and 37. After this you should be able to configure the SPI_S port and use it. Remember the Slave is limited to 3.2 MHz clock rate.

I hope this may help.

Hey, thanks for the info. The project this was for got completed a different way and I'm no longer working on it (and am no longer in possession of the source code or hardware), so there's nothing else for me to do here. Sorry for not saying that sooner and thanks for the help.