Skip to content

STM32F767 with SPI and DMA #2017

Description

@raphaelvalentin

Hi,
I am interested about SPI and DMA for a project within Arduino environment. I am at the concept for the moment and I would like to overwrite the SPIClass.
I am having a pretty bad time to figure out a working code with my SMT32F767 based on many source references that help me to understand (documentation PDF references, the web, STM-CUBE-IDE and chatGPT). My code shall run within the Arduino environment.
Below is my code for which I can not figure out why SPI works but not DMA.
Maybe, you can help me to figure out my issue.
Thanks a lot for any support !

--
Raphael.

/** STM32F767ZI MCU with LED display controlled using
 *  a list of ShiftRegister 74HC595s.
 *  To avoid library and code mixing, SPI follows STM-CUBE HAL syntax at this stage,
 *  ideally, I would like to overwrite `SPIClass` and use `SPI_HandleTypeDef
 * *getHandle(void)`; idea is taken from `STM32F4_SPI_DMA @ github.com` This
 * following code is a concept of proof and may turn to use LL. Links:
 * https://www.st.com/resource/en/reference_manual/rm0410-stm32f76xxx-and-stm32f77xxx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf
 */

#include <ArduinoTrace.h>
// #include <SPI.h> // SPI is an external library, so not loaded with the Arduino.h
#include "Arduino.h"

#define PIN_SSEL_DISPLAY (PA4)  // ==> CS = LATCH pin, signal handled via software
#define PIN_OE_DISPLAY (PC8)  // = 595 output enable/disable pin
#define PIN_ENP_DISPLAY (PC7)  // enable LDO dc power for display board

// Set up DMA
DMA_HandleTypeDef hdma_spi3_tx;
DMA_HandleTypeDef hdma_spi3_rx;
SPI_HandleTypeDef hspi3;

static void MX_DMA_Init(void);
static void MX_SPI3_Init(void);

// DMA interrupt handler
void DMA1_Stream5_IRQHandler(void) {
    HAL_DMA_IRQHandler(&hdma_spi3_tx);
    // HAL_SPI_TxRxCpltCallback(&hspi3);
}

void setup() {
    uint8_t tx_buffer[] = {0, 0, 0, 0, 0, 0, 8};  // turn on only first led
    uint8_t rx_buffer[7];  // can be used to check previous transmitted data
    uint8_t zeros[] = {0, 0, 0, 0, 0, 0, 0};

    Serial.begin(115200);

    pinMode(LED_BUILTIN, OUTPUT);

    digitalWrite(PIN_ENP_DISPLAY, HIGH);
    pinMode(PIN_ENP_DISPLAY, OUTPUT);

    digitalWrite(PIN_SSEL_DISPLAY, LOW); 
    pinMode(PIN_SSEL_DISPLAY, OUTPUT);

    digitalWrite(PIN_OE_DISPLAY, HIGH); 
    pinMode(PIN_OE_DISPLAY, OUTPUT);
    delay(100); // wait the power-up.

    MX_DMA_Init();   // first, DMA init
    MX_SPI3_Init();  // then SPI

    // link the dma with the spi
    __HAL_LINKDMA(&hspi3, hdmatx, hdma_spi3_tx);
    __HAL_LINKDMA(&hspi3, hdmarx, hdma_spi3_rx);

    __HAL_DMA_ENABLE_IT(&hdma_spi3_tx, DMA_IT_TC);

    // do not work
    // HAL_DMA_Start(&hdma_spi3_tx, (uint32_t)tx_buffer,
    // (uint32_t)&(hspi3.Instance->DR), sizeof(tx_buffer));
    /** !!! crash of the code at this point !!!
     */
    if (HAL_SPI_Transmit_DMA(&hspi3, (uint8_t*)tx_buffer, sizeof(tx_buffer)) != HAL_OK) {
        TRACE();
    }

    /** this section works using classic SPI
     */
    // HAL_SPI_Transmit(&hspi3, tx_buffer, sizeof(tx_buffer), HAL_MAX_DELAY);
    // digitalWrite(PIN_SSEL_DISPLAY, HIGH);
    // digitalWrite(PIN_SSEL_DISPLAY, LOW);
    // digitalWrite(PIN_OE_DISPLAY, LOW);

    TRACE();
    Serial.flush();
}

void loop() {
    // check if no crash
    digitalToggle(LED_BUILTIN);
    delay(500);
}

static void MX_DMA_Init(void) {
    __HAL_RCC_DMA1_CLK_ENABLE(); // clock shall be enable first

    /* Configure DMA request on DMA1_Stream5 and 0 */
    hdma_spi3_tx.Instance = DMA1_Stream5;
    hdma_spi3_tx.Init.Channel = DMA_CHANNEL_0;
    hdma_spi3_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_spi3_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi3_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi3_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_spi3_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_spi3_tx.Init.Mode = DMA_NORMAL;
    hdma_spi3_tx.Init.Priority = DMA_PRIORITY_HIGH;
    hdma_spi3_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    hdma_spi3_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
    hdma_spi3_tx.Init.MemBurst = DMA_MBURST_SINGLE;
    hdma_spi3_tx.Init.PeriphBurst = DMA_PBURST_SINGLE;
    if (HAL_DMA_Init(&hdma_spi3_tx) != HAL_OK) {
        Error_Handler();
    }

    hdma_spi3_rx.Instance = DMA1_Stream0;
    hdma_spi3_rx.Init.Channel = DMA_CHANNEL_0;
    hdma_spi3_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_spi3_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi3_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi3_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_spi3_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_spi3_rx.Init.Mode = DMA_NORMAL;
    hdma_spi3_rx.Init.Priority = DMA_PRIORITY_HIGH;
    hdma_spi3_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    hdma_spi3_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
    hdma_spi3_tx.Init.MemBurst = DMA_MBURST_SINGLE;
    hdma_spi3_tx.Init.PeriphBurst = DMA_PBURST_SINGLE;
    if (HAL_DMA_Init(&hdma_spi3_rx) != HAL_OK) {
        Error_Handler();
    }

    /* DMA interrupt init */
    /* DMA1_Stream{5,0}_IRQn interrupt configuration */
    HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);
    HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
}

void MX_SPI3_Init(void) {
    __HAL_RCC_SPI3_CLK_ENABLE();

    hspi3.Instance = SPI3;
    hspi3.Init.Mode = SPI_MODE_MASTER;
    hspi3.Init.Direction = SPI_DIRECTION_2LINES;
    hspi3.Init.DataSize = SPI_DATASIZE_8BIT;
    hspi3.Init.CLKPolarity = SPI_POLARITY_LOW;
    hspi3.Init.CLKPhase = SPI_PHASE_1EDGE;
    hspi3.Init.NSS = SPI_NSS_SOFT;
    hspi3.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
    hspi3.Init.FirstBit = SPI_FIRSTBIT_MSB;
    hspi3.Init.TIMode = SPI_TIMODE_DISABLE;
    hspi3.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    hspi3.Init.CRCPolynomial = 7;
    if (HAL_SPI_Init(&hspi3) != HAL_OK) {
        Error_Handler();
    }

    /* Configure GPIO pins for SPI3 (PC10, PC11, PC12) */
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.Pin = GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}

void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef* hspi) {
    // after RX/TX completion, latch the shiftregisters
    digitalWrite(PIN_SSEL_DISPLAY, HIGH); // latch signal after data transmitted
    digitalWrite(PIN_SSEL_DISPLAY, LOW);
    digitalWrite(PIN_OE_DISPLAY, LOW);  // = output enable
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions