cancel
Showing results for 
Search instead for 
Did you mean: 

Problem with configuring/transferring an SPI with DMA (And CRC).

MHeid.4
Associate

I can't get a data transfer over the SPI bus with my currently implemented code. I can see the CLK and CS but there is no output via MISO (only zeros are probably transferred). If I execute a transmission manually via "LL_SPI_TransmitData16", I can see this via an oscilloscope. 

The send should be triggered by an interrupt from a timer. The data come from 4 Channles of the ADC1s.

If you need more data, feel free to report. This is my first entry. 🙂 

Many greetings

Used board: STM32G071C8Ux

SPI-Configuration:

uint16_t SPI2_TX_BUFF[4] = { 0 };
 
 
/* SPI2 init function */
void spi2_init(void)
{
 
  /* USER CODE BEGIN SPI2_Init 0 */
 
  /* USER CODE END SPI2_Init 0 */
 
  LL_SPI_InitTypeDef SPI_InitStruct = {0};
 
  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
 
  /* Peripheral clock enable */
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2);
 
  LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOB);
  /**SPI2 GPIO Configuration
  PB12   ------> SPI2_NSS
  PB13   ------> SPI2_SCK
  PB14   ------> SPI2_MISO
  PB15   ------> SPI2_MOSI
  */
  GPIO_InitStruct.Pin = S_CS_Pin;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_0;
  LL_GPIO_Init(S_CS_GPIO_Port, &GPIO_InitStruct);
 
  GPIO_InitStruct.Pin = S_SCLK_Pin;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_0;
  LL_GPIO_Init(S_SCLK_GPIO_Port, &GPIO_InitStruct);
 
  GPIO_InitStruct.Pin = S_MISO_F_Pin;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_0;
  LL_GPIO_Init(S_MISO_F_GPIO_Port, &GPIO_InitStruct);
 
  GPIO_InitStruct.Pin = S_MOSI_Pin;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_0;
  LL_GPIO_Init(S_MOSI_GPIO_Port, &GPIO_InitStruct);
 
  /* SPI2 DMA Init */
 
  //spi12_dmatest();
 
    /* SPI2_TX Init */
  LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_4, LL_DMAMUX_REQ_SPI2_TX);
 
  LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_4, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
 
  LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_4, LL_DMA_PRIORITY_HIGH);
 
  LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_4, LL_DMA_MODE_NORMAL);
 
  LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_4, LL_DMA_PERIPH_NOINCREMENT);
 
  LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_4, LL_DMA_MEMORY_INCREMENT);
 
  LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_4, LL_DMA_PDATAALIGN_HALFWORD);
 
  LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_4, LL_DMA_MDATAALIGN_HALFWORD);
 
 
//  /* SPI2_RX Init */
//  LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_7, LL_DMAMUX_REQ_SPI2_RX);
//
//  LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_7, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
//
//  LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_7, LL_DMA_PRIORITY_HIGH);
//
//  LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_7, LL_DMA_MODE_NORMAL);
//
//  LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_7, LL_DMA_PERIPH_NOINCREMENT);
//
//  LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_7, LL_DMA_MEMORY_INCREMENT);
//
//  LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_7, LL_DMA_PDATAALIGN_HALFWORD);
//
//  LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_7, LL_DMA_MDATAALIGN_HALFWORD);
 
 
  /* SPI2 interrupt Init */
  NVIC_SetPriority(SPI2_IRQn, 3);
  NVIC_EnableIRQ(SPI2_IRQn);
 
  /* USER CODE BEGIN SPI2_Init 1 */
 
  /* USER CODE END SPI2_Init 1 */
  SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX;
  SPI_InitStruct.Mode = LL_SPI_MODE_MASTER;
  SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_16BIT;
  SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_LOW;
  SPI_InitStruct.ClockPhase = LL_SPI_PHASE_1EDGE;
  SPI_InitStruct.NSS = LL_SPI_NSS_HARD_OUTPUT;
  SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV8;
  SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST;
  SPI_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_ENABLE;
  SPI_InitStruct.CRCPoly = 0xED2F;
  LL_SPI_Init(SPI2, &SPI_InitStruct);
  LL_SPI_SetStandard(SPI2, LL_SPI_PROTOCOL_MOTOROLA);
  LL_SPI_SetCRCWidth(SPI2, LL_SPI_CRC_16BIT);
  LL_SPI_EnableNSSPulseMgt(SPI2);
 
  LL_SPI_EnableCRC(SPI2);
 
  LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_4, SPI2TxBufferSize);
  LL_DMA_SetPeriphAddress(DMA1, LL_DMA_CHANNEL_4, LL_SPI_DMA_GetRegAddr(SPI2));
  LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_4, (uint32_t) &SPI2_TX_BUFF[0]);
    //enable DMA Channel
  LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_4);
 
  LL_SPI_EnableDMAReq_TX(SPI2);
 
  //enable SPI2
  LL_SPI_Enable(SPI2);
}

ADC1: Memory settings with DMA settings

LL_DMA_SetDataLength(DMA1, ADC1_DMA_CHANNEL, ADC1_BUFFER_LENGTH);
  	LL_DMA_SetPeriphAddress(DMA1, ADC1_DMA_CHANNEL, LL_ADC_DMA_GetRegAddr(ADC1, LL_ADC_DMA_REG_REGULAR_DATA));
  	//LL_DMA_SetMemoryAddress(DMA1, ADC1_DMA_CHANNEL, (uint32_t)&adc1_values);
  	LL_DMA_SetMemoryAddress(DMA1, ADC1_DMA_CHANNEL, (uint32_t) &SPI2_TX_BUFF[0]);
 
  	//LL_DMA_EnableIT_HT(DMA1, ADC1_DMA_CHANNEL);
  	LL_DMA_EnableIT_TC(DMA1, ADC1_DMA_CHANNEL);
  	LL_DMA_EnableIT_TE(DMA1, ADC1_DMA_CHANNEL);
 
  	LL_DMA_EnableChannel(DMA1, ADC1_DMA_CHANNEL);
 
  	LL_ADC_Enable(ADC1);
  	while (LL_ADC_IsActiveFlag_ADRDY(ADC1) == 0);
  	LL_ADC_REG_StartConversion(ADC1);

Timer2 Interrupt:

void TIM2_IRQHandler(void)
{
  /* USER CODE BEGIN TIM2_IRQn 0 */
	LED_Red_toggle();
	LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_4);
	LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_4, SPI2TxBufferSize);
	LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_4);
	LL_TIM_ClearFlag_UPDATE(TIM2);
  /* USER CODE END TIM2_IRQn 0 */
  /* USER CODE BEGIN TIM2_IRQn 1 */
 
  /* USER CODE END TIM2_IRQn 1 */
}

1 REPLY 1
MHeid.4
Associate

The solution was simpler than expected but easier to overlook. The initialization sequence has initialized the timer, which serves as a trigger, too early. This leads to problems.