2 Replies Latest reply on Jul 26, 2016 5:42 PM by PabloM_Intel

    Quark SE MCU (Curie Arduino 101): SPI slave controller fails to transact (TXFLR & RXFLR constant)

    celskeggs

      [This is a cross-post from the Arduino 101 forums.]

       

      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.

       

      The Arduino 101 is based on the Intel Curie module, which is based on the Quark SE MCU. 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 Arduino 101 SPI library doesn't contain code for controlling the slave SPI controller, so I hacked together some code myself, which I've attached.

       

      Here's the code that I'm using (an Arduino sketch using the Arduino 101 corelibs):

       

      #include <portable.h>
      
      #define SPI_S_REG_VAL(reg) MMIO_REG_VAL_FROM_BASE(SOC_SLV_SPI_REGISTER_BASE, (reg))
      
      #define     CTRL0                 (0x00)
      #define     SSIENR                (0x08)
      #define     IMR                   (0x2C)
      #define     DR                    (0x60)
      
      void setup() {
        pinMode(MOSI, INPUT);
        pinMode(MISO, INPUT);
        pinMode(SCK, INPUT);
        pinMode(SS, INPUT);
        
        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
      
      #if 0
        SET_PIN_MODE(g_APinDescription[MOSI].ulSocPin, SPI_MUX_MODE);
        SET_PIN_MODE(g_APinDescription[MISO].ulSocPin, SPI_MUX_MODE);
        SET_PIN_MODE(g_APinDescription[SCK].ulSocPin,  SPI_MUX_MODE);
        SET_PIN_MODE(g_APinDescription[SS].ulSocPin,   SPI_MUX_MODE);
        g_APinDescription[MOSI].ulPinMode = SPI_MUX_MODE;
        g_APinDescription[MISO].ulPinMode = SPI_MUX_MODE;
        g_APinDescription[SCK].ulPinMode  = SPI_MUX_MODE;
        g_APinDescription[SS].ulPinMode  = SPI_MUX_MODE;
      #endif
      
        interrupts();
      
        while(!Serial);
        Serial.begin(115200);
        Serial.write("Configured!\n");
      
        SPI_S_REG_VAL(DR) = 0xD8; // write some sample data to the tx buffer
      }
      
      void loop() {
        delay(1000);
        Serial.println("====================");
        for (int i = 0; i < 0x60; i += 0x04) {
          Serial.write("REG ");
          Serial.print(i, HEX);
          Serial.write(" = ");
          Serial.println(SPI_S_REG_VAL(i), HEX);
        }
      }
      

       

      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.)