Go Down

Topic: Painfully slow SPI on STM32 (Read 274 times) previous topic - next topic


Hello all!

I've been working on building a project based on the Adafruit STM32F405 Feather Express. My main goal is to be able to control an 8 channel DAC, with each channel being able to put out at maximum a 4 kHz sawtooth wave independently of each other (i.e. channel 1 outputs a 255 Hz sawtooth, channel 2 outputs a 4 kHz sawtooth, etc etc). On paper, this should work, as the DAC I've selected, the LTC2636, can handle SPI bus speeds up to 50 MHz. Even if the SPI bus runs at a slower speed, I should have ample headroom to do this. The STM32F405 runs at 168 MHz, and even if the SPI bus ran at a fraction of that speed, it would still be well within 50 Mhz.

Based on this line of reasoning, I built up a PCB based on the Adafruit STM32F405 schematics (Seen here), with the only alteration being that the SPI bus going to the SPI flash instead goes to the LT2636. After a few edits to the Feather's variant.h files (changing the default SPI bus the SPI library uses to SPI1 instead of SPI2) for Arduino, I had the SPI bus communicating with the DAC. To my surprise, however, the communication speed was ***painfully*** slow. Running the code I have below, I was only able to muster 1.69 kHZ on 1 channel. At first I thought the digitalWrite function was slowing me down, but even with direct port manipulation (see other code below, I replaced digitalWrite with the sections labelled HIGH and LOW), I was still bottle-necked, with no improvement to my transfer speed. Based on readings from my (unfortunately analog) oscilloscope, as well as some tinkering with the clock speed on the code, I *think* the bus is being limited to 12 Mhz, but it could be much less, it's hard to tell with the instruments I currently have. Based on my reading of the datasheet for the STM32405, SPI1 is limited to 42 Mbits/s, which would have a clock speed well over 12 Mhz.

I don't know why this is happening, does anyone know how I can increase the transfer speed of the SPI bus? I would seriously appreciate it!

Code: [Select]
#include <SPI.h>

#define CS 7

int i = 0;

void setup() {
  pinMode(CS, OUTPUT);
  digitalWrite(CS, HIGH);

void loop() {

  if (i > 1023){
    i = 0;


void dac8Write(byte channel, int input) {
  //Warning: Channel must be less than 7!
  //0011 Command - Write to and Update DAC
  //0xxx Address - Binary address of DAC's 1-8
  //xxxxxxxxxx   - 10 bit analog value
  channel = 0x30 | channel;
  input = input << 6;
  // Send as command, address, then 10 bit value

  SPI.beginTransaction(SPISettings(50000000, MSBFIRST, SPI_MODE0));
  digitalWrite(CS, LOW);
  digitalWrite(CS, HIGH);

Code: [Select]
void setup() {
  // put your setup code here, to run once:
  pinMode(PA15, OUTPUT);
  //PA15 -> Arduino Pin 7

void loop() {
GPIOA->BSRR = 0b1000000000000000;
GPIOA->BSRR = 0b1000000000000000 << 16;



Try moving the SPI.beginTransaction() to setup() and removing SPI.endTransaction().


This has gotten a lot of responses over on https://www.eevblog.com/forum/microcontrollers/painfully-slow-spi-on-stm32f405/
Mostly of the form "you should get rid of the ST Arduino Library and HAL code and deal with the bare metal" rather than analysis of what the library is doing, but potentially useful.


So this is a cross-post with another forum. Thanks so much for wasting our time, @tyguy2.

Go Up