SPI ~CS to clock delay to long

I have been playing with SPI on the Galileo. Though the SPI clock is fast, the time from when CS goes low to when the clock & data starts is about 3ms! that is far to long to wait for the data to start. The time for the 8 bits to be clocked out is just a mere 60us. I would expect CS to data time to be much less than this. Is there a another way to shorten this time ?

    digitalWrite(CS, LOW );
    SPI.transfer(DEVICE_ID_DATA);
    digitalWrite(CS, HIGH );

3mS for a digitalWrite(), something is not right there, is there the same delay after the byte has gone?

If not the delay is in transfer(), might be worth looking at the library code to see what it does, nothing should take 3mS.


Rob

After the data, there is another 2ms before CS goes high again.
I see that there is a fastGpioSCInit(), but so far i have been unable to get it to toggle a pin.
I took a look at the SPI driver source, seems short and sweet to me, but i am not sure on that linux call stuff.

uint8_t SPIClass::transfer(uint8_t txData)
{
	uint8_t rxData = 0xFF;
	struct spi_ioc_transfer msg;

	memset(&msg, 0, sizeof(msg));
	
	msg.tx_buf = (__u64) &txData;
	msg.rx_buf = (__u64) &rxData;
	msg.len = sizeof(uint8_t);
	
	if (ioctl (this->fd, SPI_IOC_MESSAGE(1), &msg) < 0)
		trace_error("Failed to execute SPI transfer\n");

	return rxData;
}

If i change the above code to this, by adding the digitalWrite(10, LOW); directly in there it still end up being about the same.
I am thinking its the digitalWrite, that is taking so long, but i cannot find the source for it.

uint8_t SPIClass::transfer(uint8_t txData)
{
	uint8_t rxData = 0xFF;
	struct spi_ioc_transfer msg;

	memset(&msg, 0, sizeof(msg));
	
digitalWrite(10, LOW);
	msg.tx_buf = (__u64) &txData;
	msg.rx_buf = (__u64) &rxData;
	msg.len = sizeof(uint8_t);
	
	if (ioctl (this->fd, SPI_IOC_MESSAGE(1), &msg) < 0)
		trace_error("Failed to execute SPI transfer\n");
digitalWrite(10, HIGH);
	return rxData;
}

i am not sure on that linux call stuff.

Oh, I didn't realise this is running under an OS, all bets are off then I think.

Maybe a Linux guru can tell us how to bypass all the scheduling gumpf and write directly to the hardware, if that's even possible without casing a hard fault.


Rob

I believe i found the culprit. Its in the file wiring_digital.c This is where digitalWrite lives. Code at end. This IMHO is a very bloated and slow way to toggle an IO pin quickly (sure its safe) but i want fast. First it has to call pinGetIndex(pin);, then it calls digitalWriteSetVal(idx, pin, val); which is then calling fastGpioDigitalWrite(); i...yi...yi... just change the state already.....

Far to many function calls. I should be able to call fastGpioDigitalWrite directly but at the moment i have no idea what pin8 is translated to for the call .

void fastGpioDigitalWrite(register uint8_t gpio, register uint8_t val)
{
	if (val){
		*(volatile uint32_t*)fgpio.regs |= gpio;
	}else{
		*(volatile uint32_t*)fgpio.regs &= ~gpio;
	}
}
void digitalWrite(register uint8_t pin, register uint8_t val)
{
	uint32_t idx;

	if (unlikely(pin >= GPIO_TOTAL))
		return;

	if (unlikely(g_APinState[pin].uCurrentInput)) {
		if (val) {
			trace_debug("%s: input pin%u driven high: enabling "
				    "pullup", __func__, pin);
			pinMode(pin, INPUT_PULLUP);
		} else {
			trace_error("%s: input pin%u driven low!", __func__,
				    pin);
		}
		return;
	}

	if (unlikely(g_APinState[pin].uCurrentPwm)) {
		turnOffPWM(pin);
	}

	idx = pinGetIndex(pin);
	digitalWriteSetVal(idx, pin, val);

	// alias - enable w/o on Fab D for waggle of pin 20 to compensate for pin 13 error
	if (unlikely(g_APinDescription[idx].ulGPIOAlias != NONE)){
		idx = pinGetIndex(g_APinDescription[idx].ulGPIOAlias);
		digitalWriteSetVal(idx, g_APinDescription[idx].ulGPIOAlias, val);
	}
	//trace_debug("%s: pin=%d, handle=%d, val=%d", __func__, pin, handle, val);
	

}

I am not an expert on the Gallileo, but there seems to be an issue with the speed of setting the digital output bits ( which would presumably include the CS signal to the slave device, here ? ), because there is no direct GPIO, it is connected through I2C. Someone else was complaining about that, last week.

@michinyon , thanks i am aware. but still all in all if i can bypass all that function calls digitalWrite does and merely call fastGpioDigitalWrite myself, i should be able to gain allot of speed.

it is connected through I2C

Ah, is it the Gallileo that does all the shield IO through an IO expander chip? I knew one of the recent boards did that.


Rob