Skip to main content
Visitor II
December 18, 2024
Question

STM32G4 trigger SPI-DMA transfer with timer

  • December 18, 2024
  • 3 replies
  • 984 views

Hello,

I want to trigger a SPI-transfer with a timer. Its like in this post:

https://community.st.com/t5/stm32-mcus-embedded-software/stm32g4-trigger-dma-request-from-spi-to-memory-with-timer/td-p/726370

but I want that an output compare of a timer that triggers an SPI-DMA transfer. The SPI in the STM should run as a slave.

An external ADC is always triggererd from an other timer an sends his data on the SPI as a master. The SPI in the STM should read 1034x16bit values in an buffer.

I began to try it with CUBE-IDE and HAL functions. Than I found this thread here and wrote it for my application (see code below) but also with these functions i could not start the SPI-DMA transfer.

 

Is it not possible to start a spi-dma-slave for 1034 values?

Many thanks.

 

 

 

uint16_t circular_buffer[1034];

void acq_configure_adc_transfer()
{
// Read SPI1 data after rx to buffer
DMA1_Channel2->CCR = 0x0; //Disable DMA stream
DMA1_Channel2->CPAR = (uint32_t)&SPI1->DR; //Set peripheral data register as destination
DMA1_Channel2->CMAR = (uint32_t)&circular_buffer; //Set source memory region
DMA1_Channel2->CNDTR = sizeof(circular_buffer) ; //Number of items to transfer

DMA1_Channel2->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_ENABLE | //Do increment memory
DMA_CCR_PSIZE_0 | //Peripheral data size 0 = 16bit , 1 = 32bit
DMA_CCR_MSIZE_0 | //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;

DMAMUX1_Channel1->CCR = 0;
DMAMUX1_Channel1->CCR |= DMA_REQUEST_SPI1_RX | DMAMUX_CxCR_EGE;

 

HAL_TIM_Base_Start(&htim1); //Start Timer

//Reset SPI1 Configuration Register
SPI1->CR1 = 0;
SPI1->CR2 = SPI_CR2_RXDMAEN | SPI_CR2_TXDMAEN | SPI_CR2_NSSP | SPI_CR2_SSOE | SPI_DATASIZE_16BIT; // TXDMAEN: Enable TX dma, SSOE:SSoutputenable, , Data frame format 16bit
SPI1->CR1 = SPI_CR1_SPE; //Enable SPI, configuration as slaver

//Reset Timer Configuration Registers
TIM1->CR1 = 0;
TIM1->CR2 = 0;

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

TIM1->PSC = 500; //Set the prescaler
TIM1->ARR = 1000; //Set the autoreload value (timer interval)

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

}

 

 

 

    This topic has been closed for replies.

    3 replies

    Super User
    December 18, 2024

    A transfer of 1034 elements is possible. The code configures 2068 transfers, not 1034. sizeof(x) returns the size of x in bytes, not the number of elements.

    You don't configure the DMA to send to SPI->DR in response to a trigger anywhere. DMA1_Channel1 is not configured.

    SmallfaceAuthor
    Visitor II
    December 19, 2024

    Hello TDK,

    Thank you for your help.

    I can try your corrections first in the next year, I will try it first with a timer overrun like in the sample code

    But

    I thought in case I configurate the SPI as a slave I dont need the DMA1_Channel1, because I just recieve data.

    Perhaps I dont need to set: SPI_CR2_TXDMAEN

     

    I also need the HAL_SPI_RxCpltCallback function that after a transfer i can copy the recieved data to another memory.

    Which bit must I set so after a transfer the code goes to HAL_SPI_RxCpltCallback.

     

    I tried it also to start the SPI DMA read with the cubeMX:

    The trigger was here Interrupt from the Input EXTI0, even here it does not worked.

    I init it in the main-function with:

    #define SIZE_SPI_ADS8509 1036
    
    uint16_t aRxBuffer_SPI_ADS8509[SIZE_SPI_ADS8509];
    
    ret = HAL_SPI_Receive_DMA(&hspi2, (uint8_t *)aRxBuffer_SPI_ADS8509, SIZE_SPI_ADS8509);

    Smallface_1-1734619166010.pngSmallface_2-1734619184589.png

     

     

    Super User
    December 20, 2024

    Ahh, it's a slave. I missed that. If you're just receiving, then you don't need to worry about TX at all.

    In that case, I don't understand what TIM1 is doing here. If you want to receive SPI data into a circular buffer, that can be done without a timer.

    If your register level code isn't working, I would suggest coding it up using CubeMX and HAL and HAL_SPI_TransmitReceive_DMA(...), and then copying those register settings. It should be straightforward