cancel
Showing results for 
Search instead for 
Did you mean: 

Timer Trigger DMA Tx transfer for SPI2

saiteja_JDHL
Associate II

Hi there,

Iam using STM32F407ZGT6 controller, and we're interfacing DAC (MCP4902) with SPI2 and SPI2 is connected to DMA1.

 

I need to transfer data in a circular mode using DMA1 to DAC using SPI, i have gone through the reference manual only TIM1 and TIM8 are the advance timers and having PWM mode and it is connected to DMA2.

Here iam toggling cs pin and need to transfer data with this function TIM_DMACmd(TIM8, TIM_DMA_Update, ENABLE);  without enabling this  SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);

Can you please suggest me how Timer Trigger DMA for SPI 2 can be configured.



 

 

11 REPLIES 11

You don't need TIM1/TIM8 for that. DMA1 Streams (possibly triggered by timers on APB1) can write on their Peripheral port to peripherals at APB1, such as SPI2.

The usual limitation what you may have in mind is, that DMA1 cannot write to GPIO.

JW

 

saiteja_JDHL
Associate II

Could you please help me on this.

Do you have any specific example on spi tx transfer with DMA timer request transfer for stm32f407 standard peripheral library.

iam using SPI-2 here i dont know which timer can support timer request transfer.

> Do you have any specific example

No. It is not any different from any DMA example, if you set properly the DMA pointer registers.

I don't use SPL. It's been deprecated by ST for around 10 years now...

JW

please find the code can i know where exactly going wrong ?

 

void SigGenInitSigGen(void) {
uint16_t tempPrescalerValue = 0;
SigGenSpiInitData_u tempInitData;
 
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM12, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
// RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); //
 
IoSpiGpioInit();
 
/*for spi2 modified by sai*/
    SPI_I2S_DeInit(SPI2);
tempInitData.spiInitStructure.SPI_Direction = SPI_Direction_1Line_Tx;
tempInitData.spiInitStructure.SPI_DataSize = SPI_DataSize_16b;
tempInitData.spiInitStructure.SPI_CPOL = SPI_CPOL_Low;
tempInitData.spiInitStructure.SPI_CPHA = SPI_CPHA_1Edge;
tempInitData.spiInitStructure.SPI_NSS = SPI_NSS_Soft;
tempInitData.spiInitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
tempInitData.spiInitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
tempInitData.spiInitStructure.SPI_CRCPolynomial = 7;
tempInitData.spiInitStructure.SPI_Mode = SPI_Mode_Master;
    SPI_Init(SPI2, &(tempInitData.spiInitStructure));
SPI_Cmd(SPI2, ENABLE);
 
tempPrescalerValue = (uint16_t)(SystemCoreClock / 72000000) - 1;
// Configure Timer 3 to generate DMA requests
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = CONF_SIGGEN_GEN_PERIOD; // Set the period according to your requirement
TIM_TimeBaseStructure.TIM_Prescaler = tempPrescalerValue; // Set the prescaler according to your clock
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_DMACmd(TIM3, TIM_DMA_Update, ENABLE); // Enable DMA request on timer update
TIM_Cmd(TIM3, ENABLE); // Start the timer
// memset(&tempInitData, 0x00, sizeof(SigGenSpiInitData_u));
 
DMA_InitTypeDef DMA_InitStructure;
DMA_DeInit(DMA1_Stream4); // De-initialize the DMA Stream (DMA1_Stream4 for SPI2 TX)
DMA_InitStructure.DMA_Channel = DMA_Channel_0; // Channel selection
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI2->DR; // SPI2 data register address
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)m_SigGenGenBuffer_ch1; // Memory buffer address
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; // Data direction: Memory to Peripheral
DMA_InitStructure.DMA_BufferSize = CONF_SIGGEN_GEN_BUFFER_SIZE; // Buffer size
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // Peripheral increment mode
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // Memory increment mode
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // Peripheral data size (16 bits)
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; // Memory data size (16 bits)
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // Circular mode
DMA_InitStructure.DMA_Priority = DMA_Priority_High; // Priority level
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; // FIFO mode
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; // FIFO threshold
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; // Memory burst
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; // Peripheral burst
DMA_Init(DMA1_Stream4, &DMA_InitStructure);
DMA_Cmd(DMA1_Stream4, ENABLE); // Enable the DMA Stream
    DMA_ITConfig(DMA1_Stream4, DMA_IT_HT|DMA_IT_TC, ENABLE); // Enable DMA transfer complete interrupt
NVIC_EnableIRQ(DMA1_Stream4_IRQn); // Enable DMA1 Stream4 IRQ in NVIC
 
// Configure Timer 12 to toggle CS pin
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure2;
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_TimeBaseStructure2.TIM_Period =  CONF_SIGGEN_GEN_PERIOD; // Set the period according to your requirement
TIM_TimeBaseStructure2.TIM_Prescaler = tempPrescalerValue; // Set the prescaler according to your clock
TIM_TimeBaseStructure2.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure2.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM12, &TIM_TimeBaseStructure2);
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = ( CONF_SIGGEN_GEN_PERIOD * 7 / 10 ); // Adjust the pulse width as needed
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
TIM_OC1Init(TIM12, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM12, TIM_OCPreload_Disable);
TIM_ARRPreloadConfig(TIM12, ENABLE);
TIM_Cmd(TIM12, ENABLE); // Start Timer 12
 
 
 
 
 
}
 
void DMA1_Stream4_IRQHandler(void)
{
    if (DMA_GetFlagStatus(DMA1_Stream4, DMA_FLAG_HTIF4) != RESET)
    {
        // Clear DMA transfer complete flag
        DMA_ClearFlag(DMA1_Stream4, DMA_FLAG_HTIF4);
 
      m_SigGenTempGenBufferPtr_ch1 = m_SigGenPingGenBufferPtr_ch1;
      m_SigGenData_Op1.ptrCallBackInitGenBuffer();
 
 
    }
      if(DMA_GetFlagStatus(DMA1_Stream4, DMA_FLAG_TCIF4) != RESET)
      {
       DMA_ClearFlag(DMA1_Stream4, DMA_FLAG_TCIF4);
       m_SigGenTempGenBufferPtr_ch1 = m_SigGenPongGenBufferPtr_ch1;
       m_SigGenData_Op1.ptrCallBackInitGenBuffer();
 
      }
 
 
}

 

i have to transfer buffer without enabling SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);

but in my case spi is working when this function " SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);"

is calling .

> (DMA1_Stream4 for SPI2 TX)

No.

It's the trigger source - here, TIM3_UP - which determines the selection of DMA Stream (and Channel), so you have to use DMA1_Stream2 with Channel5.

JW

modified as per your comment but still not working 

> still not working

What does that mean? No output on SPI pins whatsoever?

I don't use SPL so don't quite understand your code (nor am I willing to study it in depth).

Read out and check/post relevant TIM, DMA and SPI registers content.

JW

saiteja_JDHL
Associate II

Yes SPI is not working no signals on SPI..

or please check who can have knowledge on SPL in your team.

 

Thanks for the help..