2026-05-26 2:33 PM
Hello!
I'm having issues having a successful configuration for the setup I need: an SPI TX transaction shall occur through DMA once a timer has reached its overflow count. The timer is then reloaded and proceeds to do cyclical SPI TX transactions. I need this to occur on a TIM Update Event due to a timer synchronization setup I have in place to respect strict timing restrictions.
I have tried several configurations, but overall I understand this to be the process:
All peripherals are started and enabled, but I see no clocks being generated nor data getting to the SPI's TXDR register. The SPI reports available space for TX in the status register, but nothing else. Here's an extract of the configuration I have tried
uint8_t spi_dummy_data = 0xAB; // data to send
hspi1.Instance->CR1 = 0; //turn off
hspi1.Instance->CFG1 = (0 << SPI_CFG1_BPASS_Pos) // do not bypass psc
| (3 << SPI_CFG1_MBR_Pos) // psc by 1/8
| (7UL << SPI_CFG1_DSIZE_Pos) // 8 bits in a frame
| (0 << SPI_CFG1_CRCEN_Pos) // crc disabled
| (0 << SPI_CFG1_FTHLV_Pos) //1 byte FIFO threshold level
| SPI_CFG1_TXDMAEN; //enable the dma stream
hspi1.Instance->CFG2 = SPI_CFG2_MASTER | SPI_CFG2_SSOE; // master, ss driven by peripheral
hspi1.Instance->CR2 = 8;
hspi1.Instance->CR1 |= SPI_CR1_SPE; // enable the peripheral
hspi1.Instance->CR1 |= SPI_CR1_CSTART; //start
// DMA Setup
LLItem_t dma_ch1 = {
.CTR1 = (0 << DMA_CTR1_DBL_1_Pos) // destination burst length - 1
|(0 << DMA_CTR1_DINC_Pos) // fixed burst @ destination
|(0b11 << DMA_CTR1_DDW_LOG2_Pos) // the destination is 32 bit aligned
|(0 << DMA_CTR1_SBL_1_Pos) // // source burst length -1
|(1 << DMA_CTR1_SINC_Pos) // increment addr at source (for buffer)
|(0b00 << DMA_CTR1_SDW_LOG2_Pos), // we send a single byte
.CTR2 = (0b00 << DMA_CTR2_TRIGM_Pos)
|(1 << DMA_CTR2_TRIGPOL_Pos) // trigger on rising edge
|(47 << DMA_CTR2_TRIGSEL_Pos) // tim2_trgo trigger selection
|(52 << DMA_CTR2_REQSEL_Pos), //spi tx requested
.CBR1 = 1, //1 byte
};
handle_GPDMA1_Channel1.Instance->CCR |= DMA_CCR_PRIO | 1 << DMA_CCR_LSM_Pos;
handle_GPDMA1_Channel1.Instance->CTR1 = dma_ch1.CTR1;
handle_GPDMA1_Channel1.Instance->CTR2 = dma_ch1.CTR2;
handle_GPDMA1_Channel1.Instance->CBR1 = dma_ch1.CBR1;
handle_GPDMA1_Channel1.Instance->CDAR = (uint32_t)&SPI1->TXDR;
handle_GPDMA1_Channel1.Instance->CSAR = (uint32_t)&spi_dummy_data;
handle_GPDMA1_Channel1.Instance->CCR |= DMA_CCR_EN; //enable the DMA
// TIM 2 Setup
htim2.Instance->CR1 = 0;
htim2.Instance->ARR = 599;
htim2.Instance->CCR2 = 145;
htim2.Instance->EGR = TIM_EGR_UG; // reinitialize with ARR value
htim2.Instance->SR = 0; // clear all flags
htim2.Instance->CCER = TIM_CCER_CC2E; //turn on CH2 PWM
htim2.Instance->CR2 = (0b010 << TIM_CR2_MMS_Pos); // update event
htim2.Instance->DIER = (1 << TIM_DIER_UDE_Pos); // enable dma requests
htim2.Instance->CR1 = (TIM_CR1_CEN | TIM_CR1_ARPE); // arr register is buffered and we turn on the tim
This occurs before entering the endless loop, overriding anything set by CubeMX.
I have previously been successful configuring the DMA on SPI RX and I have confirmed TIM2's trigger is being set and have used it to trigger other timers, so my bet is I have a bad/mismatch setup regarding the packing of the data at the SPI and DMA level.
Any recommendations or guidance is highly appreciated!