2024-09-30 02:27 PM - edited 2024-09-30 03:36 PM
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
}
Solved! Go to Solution.
2024-10-01 02:09 AM
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
2024-10-01 02:09 AM
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
2024-10-01 03:46 AM
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