cancel
Showing results for 
Search instead for 
Did you mean: 

How To use software NSS using SPI DMA with STM32G474

Lkim.1
Associate II

I'm using STM32G474 and I want to use SPI DMA with ltc2344-16 (ADC chip)

I can send and receive data through SPI using below codes. (LL)

void ADC_RECEIVE(uint8_t data_in)
{
	uint16_t registor = 0;
	uint16_t part[6]= {0,0,0,0,0,0};
 
	if(data_in == 0)
		registor = 0x0000;	//000 000 000 000 // 0000 0000 0000
	else if(data_in == 1)
		registor = 0x2490;	//001 001 001 001 // 0010 0100 1001
	else if(data_in == 2)
		registor = 0x4920;	//010 010 010 010 // 0100 1001 0010
	else if(data_in == 3)
		registor = 0x6DB0;	//011 011 011 011 // 0110 1101 1011
	else if(data_in == 4)
		registor = 0x9240;	//100 100 100 100 // 1001 0010 0100
	else if(data_in == 5)
		registor = 0xB6D0;	//101 101 101 101 // 1011 0110 1101
	else if(data_in == 6)
		registor = 0xDB60;	//110 110 110 110 // 1101 1011 0110
	else if(data_in == 7)
		registor = 0xFFF0;	//111 111 111 111 // 1111 1111 1111
 
	LL_GPIO_ResetOutputPin(ADC_NSS_GPIO_Port, ADC_NSS_Pin);
 
	LL_GPIO_SetOutputPin(ADC_CNV_GPIO_Port, ADC_CNV_Pin);
 
	LL_GPIO_ResetOutputPin(ADC_CNV_GPIO_Port, ADC_CNV_Pin);
 
	while(LL_GPIO_IsInputPinSet(ADC_BUSY_GPIO_Port, ADC_BUSY_Pin));
 
	while(!LL_SPI_IsActiveFlag_TXE(SPI4));
	LL_SPI_TransmitData16(SPI4, registor); //B6D
 
	while(!LL_SPI_IsActiveFlag_RXNE(SPI4));
	part[0]=LL_SPI_ReceiveData16(SPI4);
 
	for(int i=0;i<5;i++)
	{
		while(!LL_SPI_IsActiveFlag_TXE(SPI4));
		LL_SPI_TransmitData16(SPI4, 0x0000);
 
		while(!LL_SPI_IsActiveFlag_RXNE(SPI4));
		part[i+1]=LL_SPI_ReceiveData16(SPI4);
	}
 
	LL_GPIO_SetOutputPin(ADC_NSS_GPIO_Port, ADC_NSS_Pin);
}

I have to control several pins before send data.

Q1. if I use SPI DMA , how can I know where should I put code which control several pins (NSS pin, CNV pin, check BUSY pin )?

Q2. if I use SPI DMA and Control NSS pin, should I have to set DMA interrupt?

Q3. In SPI DMA, how can I know when a data start to send and end ?

Q4. if I have to set interrupt , should I set rx, tx interrupt both?

ADD

spi setting is here (Disable DMA)

static void MX_SPI4_Init(void)
{
 
  /* USER CODE BEGIN SPI4_Init 0 */
 
  /* USER CODE END SPI4_Init 0 */
 
  LL_SPI_InitTypeDef SPI_InitStruct = {0};
 
  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
 
  /* Peripheral clock enable */
  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI4);
 
  LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOE);
  /**SPI4 GPIO Configuration
  PE2   ------> SPI4_SCK
  PE5   ------> SPI4_MISO
  PE6   ------> SPI4_MOSI
  */
  GPIO_InitStruct.Pin = ADC_SCK_Pin;
  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_5;
  LL_GPIO_Init(ADC_SCK_GPIO_Port, &GPIO_InitStruct);
 
  GPIO_InitStruct.Pin = ADC_MISO_Pin;
  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_5;
  LL_GPIO_Init(ADC_MISO_GPIO_Port, &GPIO_InitStruct);
 
  GPIO_InitStruct.Pin = ADC_MOSI_Pin;
  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_5;
  LL_GPIO_Init(ADC_MOSI_GPIO_Port, &GPIO_InitStruct);
 
  /* USER CODE BEGIN SPI4_Init 1 */
 
  /* USER CODE END SPI4_Init 1 */
  /* SPI4 parameter configuration*/
  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_HIGH;
  SPI_InitStruct.ClockPhase = LL_SPI_PHASE_1EDGE;
  SPI_InitStruct.NSS = LL_SPI_NSS_SOFT;
  SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV8;
  SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST;
  SPI_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;
  SPI_InitStruct.CRCPoly = 7;
  LL_SPI_Init(SPI4, &SPI_InitStruct);
  LL_SPI_SetStandard(SPI4, LL_SPI_PROTOCOL_MOTOROLA);
  LL_SPI_DisableNSSPulseMgt(SPI4);
  /* USER CODE BEGIN SPI4_Init 2 */
 
  /* USER CODE END SPI4_Init 2 */
 
}

1 REPLY 1

There are two DMAs involved - one for Tx and one for Rx. Generally,

  • toggle whatever pins you want (do you really want to wait the conversion time, i.e. cca 500ns, in a loop? Maybe yes, alternative is a pin-interrupt but its overhead may be of similar time)
  • set up and enable Rx SPI DMA
  • set up and enable Tx SPI DMA, that starts to write into SPI_DR thus determines the starting point of the whole transaction
  • when Rx SPI finishes i.e. its DMA Transfer Complete interrupt is thrown, you're finished and can wiggle any pin you need

For a few transfers at high bitrate, the whole procedure with DMA may have too high software overhead and be not worth it. You decide.

> Q2. if I use SPI DMA and Control NSS pin, should I have to set DMA interrupt?

What is "Control NSS pin"? If it is some Cube lingo, please don't use it, not everybody uses Cube (and Cube makes the mistake of inventing these terms) - use the terminology from Reference Manual throughout. If you mean some of the methods how SPI controls NSS pin in hardware, they are mostly useless.

JW