cancel
Showing results for 
Search instead for 
Did you mean: 

STM32G4 trigger DMA request from SPI to Memory with timer

mariankeller
Associate

Hello,

I'm trying to get SPI to receive data from an ADC in a periodic interval, and must not use interrupts, as the whole application is already pushing the upper limit of what the MCU can handle. The code below is just a rough test, adapted from what I found in another thread in this forum. However, I still can't get it to work. Timer runs, DMA and DMAMUX seem to get configured, but nothing happens on the SPI CLK. Any ideas?

 

void acq_configure_adc_transfer()
{
	uint32_t circular_buffer[10];

	__HAL_RCC_DMAMUX1_CLK_ENABLE();
	__HAL_RCC_DMA1_CLK_ENABLE();
	__HAL_RCC_SPI1_CLK_ENABLE();
	__HAL_RCC_TIM1_CLK_ENABLE();

	DMA1_Channel1->CCR = 0x0;	//Disable DMA stream

	DMA1_Channel1->CPAR = (uint32_t)&SPI1->DR;   	                    //Set source memory region
	DMA1_Channel1->CMAR = (uint32_t)&circular_buffer;	                //Set peripheral data register as destination
	DMA1_Channel1->CNDTR = sizeof(circular_buffer) ; 		//Number of items to transfer

	//NVIC_EnableIRQ(DMA1_Channel2_IRQn);	     	//Enable interrupt for DMA Channel 2, to deal with finished transfers

	DMA1_Channel1->CCR =
			DMA_CCR_EN | 			    //Enable
			DMA_CCR_HTIE | 			    //half transfer interrupt enable
			DMA_CCR_TCIE | 			    //transfer complete interrupt enable
			DMA_CCR_CIRC | 		     	//DMA Circular mode
			DMA_PINC_DISABLE | 		    //Do not increment peripheral
			DMA_MINC_DISABLE | 		    //Do not increment memory  //DMA_MINC_DISABLE
			DMA_CCR_PSIZE_1 | 		    //Peripheral data size 0 = 16bit , 1 = 32bit
			DMA_CCR_MSIZE_1 | 		    //Memory data size 0 = 16bit , 1 = 32bit
			DMA_PRIORITY_VERY_HIGH;  	//DMA Priority

	DMAMUX1_Channel0->CCR = 0;
	DMAMUX1_Channel0->CCR |= DMA_REQUEST_TIM1_UP | DMAMUX_CxCR_EGE;

	HAL_TIM_Base_Start(&htim1);	//Start Timer

	//Reset SPI1 Configuration Register (-> this will disable the SPI1)
	SPI1->CR1 = 0b00000000;
	//SPI1->CR2 = SPI_CR2_TXEIE | SPI_CR2_TXDMAEN | SPI_CR2_SSOE;	//TXEIE:Txbuffer empty interrupt enable, TXDMAEN: Enable TX dma, SSOE:SSoutputenable
	SPI1->CR2 = SPI_CR2_RXNEIE | SPI_CR2_RXDMAEN;	//TXEIE:Txbuffer empty interrupt enable, TXDMAEN: Enable TX dma, SSOE:SSoutputenable

	SPI1->CR1 = SPI_CR1_MSTR | SPI_CR1_SPE | SPI_DATASIZE_16BIT; //Enable SPI, configuration as master, Data frame format 16bit
	//Reset Timer Configuration Registers (-> this will disable the timer)
	TIM1->CR1 = 0b00000000;
	TIM1->CR2 = 0b00000000;

	TIM1->DIER = TIM_DIER_UDE; //UDE Update DMA request enable

	TIM1->PSC = 500; 			//Set the prescaler
	TIM1->ARR = 1000; 			//Set the autoreload value

	TIM1->CR1 = TIM_CR1_CEN | TIM_CR1_ARPE;	//the CEN is set (Counter enable) and ARPE:Auto-reloadpreloadenable is buffered (TIMx_ARR register is buffered)
	//Timer is now started and triggers SPI at each overflow

}

 

1 REPLY 1

SPI won't clock if you read out its data register (using DMA or processor, it doesn't matter).

You need to set up two DMAs: one, upon trigger from the timer, transfers a dummy value to SPI data register to start the SPI clocking, and then if SPI finishes the clocking, there's a data read in in the SPI's data register, and the second DMA, upon trigger from SPI, transfers the read data from that SPI data register to memory.

You don't want the buffer to be a local variable, and you want to increment DMA MINC.

JW