cancel
Showing results for 
Search instead for 
Did you mean: 

DMA to SPI triggered by Timer STM32H723

thomas23
Associate II

Hi All,

I am trying to send data to SPI1 via DMA1 Stream 0, using a timer to trigger DMA.

Currently, I have used TIM4 Channel2 and Enabled DMA Update with DIER register (UDE bit).

DMAMUX1 Channel 0 Request is set to 32.

So far, this part seems to work: I have used a LED to monitor HT and TC flags of DMA, and it toggles at the speed it should.

But the SPI does not send anything (I checked the MOSI and SCK lines with an oscilloscope)... as if TXDR register was not filled by the DMA.

Do you have an idea of what is happening?

I have checked that my buffer xyDacData is correct (not null), and also I monitored SPI CR1 as well as SPI SR with SWD debug, all seems OK (SR is null, CR1 shows SPE and CSTART at 1).

Thank you!

(About SSM and SSI bits, I have set these to test, but they should be useless, since I am in master transmitter mode..

 

/*
 * FBx_XY.c
 *
 *  Created on: Sep 10, 2024
 *      Author: Thomas
 */


#include "main.h"

#define XY_SYNC_BITS 	(24 + 8) 	// Take some margin
#define DURATION_SPI_SEQ_CLK 	(TIMERS_CLK / 25000000 * XY_SYNC_BITS) 	// 25MHz is the SPI Speed

static void XY_Init_DMA();
static void XY_Init_Sync();
static void XY_Init_SPI();

__IO uint32_t xyDacData[BASE_POINT_LOAD * 2 * 2] = {0};
//__IO uint32_t testDacData[BASE_POINT_LOAD * 2 * 2] = {0};

/*
 * ===================
 * ===================
 */
void XY_Init()
{
	XY_Init_SPI();
	XY_Init_DMA();
	XY_Init_Sync();

	TIM4->CR1 |= TIM_CR1_CEN;
}

/*
 * ======================
 * DMA1 Stream0
 * Channel 32
 * ======================
 */
void XY_Init_DMA()
{
	__HAL_RCC_DMA1_CLK_ENABLE();
	// Circular mode. HT and TC are used to fill the buffer safely

	DMA1_Stream0->CR |= (0b10 << DMA_SxCR_PL_Pos); 			// High Priority Channel
	DMA1_Stream0->CR |= (0b10 << DMA_SxCR_MSIZE_Pos); 		// 32-bits Memory Size
	DMA1_Stream0->CR |= (0b10 << DMA_SxCR_PSIZE_Pos); 		// 32-bits Peripheral Size
	DMA1_Stream0->CR |= DMA_SxCR_CIRC;						//
	DMA1_Stream0->CR |= DMA_SxCR_MINC;						// Memory Auto-Increment
	DMA1_Stream0->CR |= (0b01 << DMA_SxCR_DIR_Pos);			// Read from Memory to Peripheral
	//DMA1_Stream0->CR |= DMA_SxCR_HTIE;						// Interrupt enable
	//DMA1_Stream0->CR |= DMA_SxCR_TCIE;						// Interrupt enable

	DMA1_Stream0->NDTR = BASE_POINT_LOAD * 2 * 2; 				// Number of points in the frame. x2 because of X and Y.

	DMA1_Stream0->M0AR = (uint32_t) xyDacData; 				// Initial Address for Memory
	DMA1_Stream0->PAR = (uint32_t) &(SPI1->TXDR); 		//

	DMAMUX1_Channel0->CCR |= 32 << DMAMUX_CxCR_DMAREQ_ID_Pos; 	// TIM4_UP = 32

	DMA1_Stream0->CR |= DMA_SxCR_EN;						// Enable, waits for TIM trigger

	// DMAMUX32 = TIM4 UP
	// DMAMUX30 = TIM4 CH2
}

/*
 * ======================
 * PG11 SPI1 SCK
 * PB5 SPI1 MOSI
 * SPI Speed Up to 30MHz
 * ======================
 */
void XY_Init_SPI()
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};

	__HAL_RCC_SPI1_CLK_ENABLE();

	GPIO_InitStruct.Pin = GPIO_PIN_11;
	GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
	GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
	HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);

	GPIO_InitStruct.Pin = GPIO_PIN_5;
	GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
	GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

	// SPI CLK 200MHz
	SPI1->CR1 = 0;
	SPI1->CR2 = 0;
	SPI1->CFG1 = 0;
	SPI1->CFG2 = 0;
	//SPI1->CFG1 |= SPI_CFG1_TXDMAEN; 	// ?? No need, DMA trigger is generated by TIM4
	SPI1->CFG1 |= (24 - 1) << SPI_CFG1_DSIZE_Pos; 	// 24 bits data
	SPI1->CFG1 |= 0b10 << SPI_CFG1_MBR_Pos; 	// Master clock / 8 = 25MHz
	SPI1->CFG2 |= SPI_CFG2_MASTER;
	SPI1->CFG2 |= 0b01 << SPI_CFG2_COMM_Pos; 	// Simplex transmitter
	//SPI1->CFG2 |= SPI_CFG2_SSIOP; 				// Software manageemnt (to disable SS pin)
	SPI1->CFG2 |= SPI_CFG2_SSM; 				// Software manageemnt (to disable SS pin)
	SPI1->CFG2 |= 0b10 << SPI_CFG2_MSSI_Pos;
	SPI1->IFCR = SPI_IFCR_MODFC;

	SPI1->CR1 |= SPI_CR1_SPE; 	// SPI Enable, waiting for data
	SPI1->CR1 |= SPI_CR1_CSTART;

	SPI1->CR1 |= SPI_CR1_SSI; 				// Software manageemnt (to disable SS pin)
}

/*
 * ===================
 * PB7 TIM4 CH2
 * ===================
 */
void XY_Init_Sync()
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};

	__HAL_RCC_TIM4_CLK_ENABLE();

	GPIO_InitStruct.Pin = GPIO_PIN_7;
	GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
	GPIO_InitStruct.Alternate = GPIO_AF2_TIM4;
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

	TIM4->CR1 = 0;
	TIM4->CR1 &= ~TIM_CR1_CKD; 					// Clock division 1
	TIM4->PSC = 0; 								// Time base full speed for high accuracy on scan rate
	TIM4->ARR = (TIMERS_CLK / (SCAN_RATE * 2)) - 1; 	// Period. Scan rate x2 because we have to transfer X and Y

	//TIM4->BDTR |= TIM_BDTR_MOE; 		// Main Output Enable (used for output on Pin)

	//TIM4->CR2 &= ~TIM_CR2_OIS2; 		// Idle State RESET
	TIM4->CCMR1 |= (TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_2); 	// PWM1
	TIM4->CCMR1 |= TIM_CCMR1_OC2PE; 	// OC CCR2 preload enable (must be enabled for PWM mode).
	TIM4->CCMR1 &= ~TIM_CCMR1_CC2S; 	// Channel configured as Output

	TIM4->DIER |= TIM_DIER_UDE;

	TIM4->CCR2 = DURATION_SPI_SEQ_CLK; 		// Set Period
	TIM4->CCER |= TIM_CCER_CC2P; 			// Inverted polarity
	TIM4->CCER |= TIM_CCER_CC2E; 	// Enable OC2
}

 

 

1 ACCEPTED SOLUTION

Accepted Solutions

The 'H7 SPI is an overcomplicated beast (I don't use it but have had a look at the SPI chapter in RM and didn't like what I saw there).

Polling (i.e. writing to SPI using processor rather than DMA) with these settings works?

> About SSM and SSI bits, I have set these to test, but they should be useless, since I am in master transmitter mode..

You shall set them before enabling SPI, or maybe even before setting the master mode, otherwise, if given pin is low (or even unconfigured, which is internally low), SPI will immediately switch to slave mode - you can check this by observing the respective bit in status register.

JW

View solution in original post

2 REPLIES 2

The 'H7 SPI is an overcomplicated beast (I don't use it but have had a look at the SPI chapter in RM and didn't like what I saw there).

Polling (i.e. writing to SPI using processor rather than DMA) with these settings works?

> About SSM and SSI bits, I have set these to test, but they should be useless, since I am in master transmitter mode..

You shall set them before enabling SPI, or maybe even before setting the master mode, otherwise, if given pin is low (or even unconfigured, which is internally low), SPI will immediately switch to slave mode - you can check this by observing the respective bit in status register.

JW

Thank you very much!

I enabled SSM and SSI bits before MASTER, and it solved the issue indeed!

(Before SPE and CSTART is not enough, FYI).

Thomas