Set spi speed to 2Mhz precise

I’m trying to implement DMX transmission on the Photon. See my older topic: Transmit DMX data with DMA

Since working with DMA, TIMERS and other GPIO stuff, is not really something I’m used to (and it seems to conflict pretty soon with Particle functions) I wanted to use SPI transfer which utilises DMA.

However I need a transferspeed of exactly 2Mhz (I use a byte array to represent the DMX bitstream. Memory is not really an issue). 2Mhz/8bit = 250.000Hz = 250kbps (baudrate of DMX).

However because the SPI1 speed is 30Mhz, I can’t reach that speed with the dividers (30/16 = 1,875Mhz.

Is there a way to modify the SPI1 speed and set it really precise?

Does anyone have other suggestions or ideas? It think bitbanging could be an option, although it think that can’t happen in the background (code examples are welcome though).

Isn’t baudrate or kbps (mark the lower case b) already based on bits rather than KB/s (kilo byte per second - mark the capital B)?
So wouldn’t you set the SPI speed to 250kHz?

And to rid you of the need to calculate prescalers and dividers you can use this overload of SPI.setClockSpeed()

SPI.setClockSpeed(250000);
1 Like

Indeed baudrate is in bits. I set the SPI speed 8 times as fast, because for convenience 1 bit is 1 byte (a byte array is easier to fill with bytes instead if bits). The array is filled with 0x00 (for 0) and 0xff (for 1).

Normally a bit takes 4us in the DMX protocol, so I send each byte eight times as fast (so it will take also 4us). That's why I need 2Mhz (8*250kHz).

The problem with setClockSpeed(250000) is that it rounds down to the nearest divider.

The clock speed cannot be set to any arbitrary value, but is set internally by using a divider (see SPI.setClockDivider()) that gives the highest clock speed not greater than the one specified.
https://docs.particle.io/reference/firmware/photon/#setclockspeed

So the closest I can get is: 30Mhz/16 = 1875000Hz = 1.875Mhz
Because: 30Mhz/8 = 3750000Hz = 3.75Mhz

As DMX is async serial (8 databits, 2 stop bits) is there any reason you’re not just using a UART to drive this? Seems easier than crafting async serial with a SPI port, and allows you to receive data too if you wanted to.

Well recently someone published an UART implementation:

I couldn't test it though, but it seems pretty straight forward.

However, I'd like that sending DMX happens in background and I think that's not the case. Besides that there is another problem and that's that DMX needs a BREAK (>88us LOW) and a MARK (>8us HIGH). So you have to change the UART to GPIO for a while and back (like the implementation in particle-simple-dmx). Because of that I suppose that not everything can happen in the background).

That's why I like the array approach that I found online and I tried to modify that for the GPIO. However because I couldn't make that happen I've tried the SPI road. Which seems a good suggestion, except that you can't set the timing precise.

I've put the code in a repo:
https://github.com/kasperkamperman/PhotonDMADMX

I tried to copy the DMA setup from the SPI3 code in the Particle Firmware, however I think it goes wrong with the connection of the timer.

https://github.com/kasperkamperman/PhotonDMADMX/blob/master/DMXDriverDMA/firmware/DMX_DMA_Out.cpp#L57