I have been trying to get SPI master transmit to work using DMA and STM32 LL drivers, on STM32G030C8.
I did get the SPI to work with LL drivers without DMA, so I believe that at least my wiring is correct.
What I have done:
Set SPI to use DMA in cubeMX by setting
SPI1_TXRequest to DMA1 channel 1Setup the transmit in code:
main.c
#include "main.h"
#include "dma.h"
#include "gpio.h"
#include "spi.h"
uint8_t test_data[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
void SystemClock_Config(void);
int main(void) {
       
        HAL_Init();
        SystemClock_Config();
        MX_GPIO_Init();
        MX_SPI1_Init();
        MX_DMA_Init();
        while (1) {
                LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_1, (uint32_t)(&test_data[0]),
                                       (uint32_t)LL_SPI_DMA_GetRegAddr(SPI1),
                                       LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_CHANNEL_1));
                LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, 8);
                LL_SPI_EnableDMAReq_TX(SPI1);
                LL_SPI_Enable(SPI1);
                LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);
                HAL_Delay(1000);
                HAL_GPIO_TogglePin(STATUS_LED_GPIO_Port, STATUS_LED_Pin);
        }
}
spi.c:
#include "spi.h"
void MX_SPI1_Init(void)
{
  LL_SPI_InitTypeDef SPI_InitStruct = {0};
  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
  GPIO_InitStruct.Pin = LL_GPIO_PIN_1;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_0;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  GPIO_InitStruct.Pin = LL_GPIO_PIN_2;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_0;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_1, LL_DMAMUX_REQ_SPI1_TX);
  LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_1, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
  LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PRIORITY_LOW);
  LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MODE_NORMAL);
  LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PERIPH_NOINCREMENT);
  LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MEMORY_INCREMENT);
  LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PDATAALIGN_BYTE);
  LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MDATAALIGN_BYTE);
  NVIC_SetPriority(SPI1_IRQn, 0);
  NVIC_EnableIRQ(SPI1_IRQn);
  SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX;
  SPI_InitStruct.Mode = LL_SPI_MODE_MASTER;
  SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_8BIT;
  SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_LOW;
  SPI_InitStruct.ClockPhase = LL_SPI_PHASE_1EDGE;
  SPI_InitStruct.NSS = LL_SPI_NSS_SOFT;
  SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV4;
  SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST;
  SPI_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;
  SPI_InitStruct.CRCPoly = 7;
  LL_SPI_Init(SPI1, &SPI_InitStruct);
  LL_SPI_SetStandard(SPI1, LL_SPI_PROTOCOL_MOTOROLA);
  LL_SPI_DisableNSSPulseMgt(SPI1);
}
dma.c:
#include "dma.h"
void MX_DMA_Init(void)
{
  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);
  NVIC_SetPriority(DMA1_Channel1_IRQn, 0);
  NVIC_EnableIRQ(DMA1_Channel1_IRQn);
}
from the reference manual I found the following steps for DMA configuration:
Channel configuration procedure The following sequence is needed to configure a DMA channel x:
- Set the peripheral register address in the
 DMA_CPARxregister. The data is moved from/to this address to/from the memory after the peripheral event, or after the channel is enabled in memory-to-memory mode.- Set the memory address in the
 DMA_CMARxregister. The data is written to/read from the memory after the peripheral event or after the channel is enabled in memory-to-memory mode.- Configure the total number of data to transfer in the
 DMA_CNDTRxregister. After each data transfer, this value is decremented.- Configure the parameters listed below in the
 DMA_CCRxregister: – the channel priority – the data transfer direction – the circular mode – the peripheral and memory incremented mode – the peripheral and memory data size – the interrupt enable at half and/or full transfer and/or transfer error- Activate the channel by setting the EN bit in the
 DMA_CCRxregister. A channel, as soon as enabled, may serve any DMA request from the peripheral connected to this channel, or may start a memory-to-memory block transfer.
To my understanding steps 1,2,3 and 5 are done in main.c, and the step 4 already in spi.c
Also in the reference manual about SPI and DMA:
A DMA access is requested when the TXE or RXNE enable bit in the
SPIx_CR2register is set. Separate requests must be issued to the Tx and Rx buffers.-In transmission, a DMA request is issued each time TXE is set to 1. The DMA then writes to the
SPIx_DRregister
and
When starting communication using DMA, to prevent DMA channel management raising error events, these steps must be followed in order:
- Enable DMA Rx buffer in the RXDMAEN bit in the SPI_CR2 register, if DMA Rx is used.
 - Enable DMA streams for Tx and Rx in DMA registers, if the streams are used.
 - Enable DMA Tx buffer in the TXDMAEN bit in the SPI_CR2 register, if DMA Tx is used.
 - Enable the SPI by setting the SPE bit.
 
In my understanding I have done all the steps, but I cannot see anything with my oscilloscope attached to SPI1 lines.
I must be missing something (or something is done in wrong order) but I cannot figure out what is wrong.
In some other questions the problem has been that the DMA channel was wrong and not supporting SPI, but in this MCU, if I understood correctly, the DMAMUX handles that, and any signal should be available in any DMA channel? (configured in spi.c)
EDIT:
Reading flags from SPI and DMA:
LL_SPI_IsActiveFlag_BSY(SPI1)                   returns 0
LL_SPI_IsEnabledDMAReq_TX(SPI1)                 returns 1
LL_SPI_IsEnabled(SPI1)                          returns 1
LL_DMA_IsEnabledChannel(DMA1, LL_DMA_CHANNEL_1) returns 1
LL_DMA_IsActiveFlag_TE1(DMA1)                   returns 0
LL_SPI_IsActiveFlag_TXE(SPI1)                   returns 1
So, everything seems to be enabled, no errors but no data is transferred!
Any help is appreciated! Thanks!
