SPI, write 24bits?

DrM

Well-known member
Hi,

I am designing a board based on the DAC82001. It is a 16 bit DAC with SPI.

The figures below show the data protocol. It needs a 24 bits for each instruction cycle. The SPI library has transfer() for one byte, and transfer16() for two. Is there a transfer24(), or better yet, a transferN( n, *bytes)? Could there be? What is involved, and where should I look in the source?

Thank you


1704668069470.png
 
Tried a quick test just now. 1 million transfers takes 1.19 seconds if done the simplest way with SPI.transfer(buffer, 3) using 30 MHz clock.

Here's the code if you want to experiment...

Code:
#include <SPI.h>

void setup() {
  pinMode(10, OUTPUT);
  digitalWriteFast(10, HIGH);
  SPI.begin();
  Serial.begin(9600);
  while (!Serial) ; // wait for Arduino Serial Monitor
  Serial.println("SPI 24 bit speed test");
  elapsedMicros usec = 0;
  for (int i=0; i < 1000000; i++) {
    unsigned char buf[3];
    buf[2] = i >> 16;
    buf[1] = i >> 8;
    buf[0] = i;
    SPI.beginTransaction(SPISettings(30000000, MSBFIRST, SPI_MODE0));
    digitalWriteFast(10, LOW);
    SPI.transfer(buf, 3);
    digitalWriteFast(10, HIGH);
    SPI.endTransaction();
  }
  float sec = (float)usec / 1.0e6f;
  Serial.print("1 million transfers took ");
  Serial.print(sec);
  Serial.println(" seconds");
}

void loop() {
}
 
If done as 1 large transaction, the time becomes only 1.05 seconds. But looking at the CS signal on my scope, the time CS is high (inactive) between transfers is under 10ns!

Code:
#include <SPI.h>

void setup() {
  pinMode(10, OUTPUT);
  digitalWriteFast(10, HIGH);
  SPI.begin();
  Serial.begin(9600);
  while (!Serial) ; // wait for Arduino Serial Monitor
  Serial.println("SPI 24 bit speed test");
  elapsedMicros usec = 0;
  SPI.beginTransaction(SPISettings(30000000, MSBFIRST, SPI_MODE0));
  for (int i=0; i < 1000000; i++) {
    unsigned char buf[3];
    buf[2] = i >> 16;
    buf[1] = i >> 8;
    buf[0] = i;
    digitalWriteFast(10, LOW);
    SPI.transfer(buf, 3);
    digitalWriteFast(10, HIGH);
  }
  SPI.endTransaction();
  float sec = (float)usec / 1.0e6f;
  Serial.print("1 million transfers took ");
  Serial.print(sec);
  Serial.println(" seconds");
}

void loop() {
}
 
Personally, on the teensy I would not use that form of transfer... Unless of course you like it overwriting your buffer.
I would use something like, SPI.transfer(txBuffer, rxBuffer, cnt);
Note both txBuffer or rxBuffer can be NULL (nullptr) and on RX if null, will not return data. if TxBuffer is null, it will use a default character...

However if your data is like stored in a uint32_t, the bytes may not come out in the order you need...

Hardware wise you can transfer 24 bits per transfer. The ILI9488 boards in SPI mode we need to send 24 bytes per pixel. If we have a large enough memory to store the pixels with 32 bits per pixel, the update Screen using DMA, is setup to send the 32 bits to SPI, and SPI is setup to transfer 24 bits of it.
 
@Paul , thank you. That is super encouraging and very useful, I was wondering what happens to the CS line between transfers. I think that means I might be able to use for the SYNC, though I could just as well tie it high. Anyway, that is probably fast enough.

@KurtE thank you, I did not see that listed in the library documentation, very nice. I agree, that is probably the interface I want to use.

Okie dokie, I'll push on with the design, hopefully finish it up tomorrow. The trick I am running into now for this part is that Vref can't be higher than VDD. So, can't run everything from just 3.3V unless Vref is lower, and can't run VDD from 5V with a 3.3V ref, and interface to 3.3V hosts because of the pull-ups. So I am thinking to use a 3.3 reference and a 3.3V LDO for VD, and power both from 5V. The alternative would be run VDD from 5V and use level converters for the PSI lines. That would be a little more flexible in case somebody wants to use it with a 5V logic (if that exists anymore in a microcontroller).

Sorry, thinking out loud. Feel free to chime in.
 
@Paul Oh I see, you were toggling CS. That is amazing actually, 10ns between transfers. Thank you. That does work out well.
 
Back
Top