Hi folks,
I had need to get SPI slave mode working on the Arduino 101 with the Intel Curie SOC. Results from forum searches and general googling around kicked up a few aborted attempts, and a couple of posts saying that it was not possible, and if SPI slave was a must-have, then you needed another Arduino type. Let me get this out of the way - this "guidance" was wrong. And it kinda annoyed me. If you're not 100% intimate with the hardware, please don't go around making blanket comments like this. These comments live forever online, and cause a great disservice to anyone attempting to get something working.
I had another Arduino - the Yun - which can not support external SPI slave operation (not strictly correct, the AR9331 puts the ATmega into SPI slave to reprogram the micro controllers prom, but since the SS is not brought out to a header pin, you can't do this externally. Can this be changed in rev. 3 of the Yun BTW?), so I was motivated to fully understand the 101's SPI subsystem.
I'd like to report that you can indeed put the 101 into SPI slave. I am attaching a proof of concept (POC) sketch that does so. The trick was to just to get the correct register configuration:
a) reading the schematics showed that the SPI slave pins and one of the SPI master's are both brought out to the standard SPI digital pins (10-13).
b) Correctly reprogram the pin multiplexers with the right functions for the slave and master controllers.
c) Configure the master pins as all inputs and configure the slave pins appropriately (i.e MISO as output, MOSI, SS and SCK as inputs).
void setup() {
noInterrupts();
// SPI1 and SPI_S share pins, so SPI1 (master) must be disabled via enabling as GPIO
SET_PIN_MODE(42, GPIO_MUX_MODE); // SPI1_MISO
SET_PIN_MODE(43, GPIO_MUX_MODE); // SPI1_MOSI
SET_PIN_MODE(44, GPIO_MUX_MODE); // SPI1_SCK
SET_PIN_MODE(45, GPIO_MUX_MODE); // SPI0_CS_B[0]
SET_PIN_MODE(46, GPIO_MUX_MODE); // SPI0_CS_B[1]
SET_PIN_MODE(47, GPIO_MUX_MODE); // SPI0_CS_B[2]
SET_PIN_MODE(48, GPIO_MUX_MODE); // SPI0_CS_B[3]
SET_MUX_IN_EN(42, true);
SET_MUX_IN_EN(43, true);
SET_MUX_IN_EN(44, true);
SET_MUX_IN_EN(45, true);
// set GPIO 0,1,2,3 for FUNCTION_2 (SPI slave)
SET_PIN_MODE(2, QRK_PMUX_SEL_MODEC); // SPI MODE (Fn 2) for SPI0_S SCK
SET_PIN_MODE(1, QRK_PMUX_SEL_MODEC); // SPI MODE (Fn 2) for SPI0_S MISO
SET_PIN_MODE(3, QRK_PMUX_SEL_MODEC); // SPI MODE (Fn 2) for SPI0_S MOSI
SET_PIN_MODE(0, QRK_PMUX_SEL_MODEC); // SPI MODE (Fn 2) for SPI0_S CS
SET_MUX_IN_EN(2, true);
SET_MUX_IN_EN(1, false);
SET_MUX_IN_EN(3, true);
SET_MUX_IN_EN(0, true);
// disable clocks for SPI1
CLEAR_MMIO_BIT(PERIPH_CLK_GATE_CTRL, 15);
// CLEAR_MMIO_BIT(CREG, CREG_CLK_CTRL_SPI1);
// CLEAR_MMIO_BIT(SPI1.SSIENR, 0); // FIX THIS
// configure SPI slave
SPI_S_REG_VAL(SPIEN) &= ~SPI_ENABLE; // disable
SET_MMIO_BIT(PERIPH_CLK_GATE_CTRL, 16); // enable clock for SPI slave (bit 16)
SPI_S_REG_VAL(CTRL0) = ((SPI_8_BIT << 16) | (0x00 << 6)); // 8 bit frame size; SPI MODE 0
SPI_S_REG_VAL(IMR) = SPI_DISABLE_INT; // no interrupts
SPI_S_REG_VAL(SPIEN) |= SPI_ENABLE; // enable
interrupts();
Serial.begin(115200);
while(!Serial);
Serial.write("Configured!\n");
SPI_S_REG_VAL(DR) = 0xD8; // write some sample data to the tx buffer
}
The standard SPI library provides functions for SPI master operation, not SPI slave, however it provides aa huge number of very useful #defines, which I've liberally used. After configuration, the POC simply uses a polling mechanism to read the RxFIFO and rewrite the same data back to the Master. I'll work on integrating an interrupt driven Rx and Tx as the next phase, but having the configuration documented here should help other poor lost souls. Note, the attached sketch is based on some other user submitted sample code - a particular user who couldn't get it running, and I've just added the correct configuration.
One more thing to note - the Arduino 101 maximum SCK frequency when operating as a slave is 3.2MHz. Be aware of this when you set your clock divisor on your master.
I know it's not going to cure cancer or solve world hunger, but hopefully anyone in need of SPI slave operation with the 101 will stumble across this post, and at least know it is possible, and inch closer to their design goals.
A101-slave-v1.ino (3.01 KB)