2021-01-14 4:58 AM
Hello,
When I use DMA with SPI it is not working.
When I get a falling edge on DRDY this function gets called :
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == DRDY_ADC_Pin)
{
HAL_SPI_Receive_DMA(&hspi1, SPI1_RxBuffer, READBACK_LENGTH);
}
}SPI1 RX Buffer is located in a DMA accessible memory, RAM D2 (it works I checked the .map) :
uint8_t __attribute__(( section(".ramd2section"))) SPI1_RxBuffer[READBACK_LENGTH]; // SPI TxMy question is do I need to use a setup function outside of what HAL_SPI_MspInit() already does. For example HAL_MDMA_Start_IT() ?
I've red few posts with the same problem but the solution is never explicated or done not using only HAL function.
What I use :
SPI1 Master full-duplex
DMA1 Stream 2 SPI1_Rx to SPI1_RxBuffer
MDMA Stream 0 SPI1_RxBuffer to ads_buf located in DTCMRAM
2021-01-14 5:24 AM
Read out and check/post SPI and relevant DMA registers (including status) content.
JW
2021-01-14 5:31 AM
Tried adding DMAMUX init but it didnt change anything
dmamux_ReqGenParams.SignalID = 37U;
dmamux_ReqGenParams.Polarity = HAL_DMAMUX_REQ_GEN_RISING;
dmamux_ReqGenParams.RequestNumber = 1;
HAL_DMAEx_ConfigMuxRequestGenerator(&hdma_spi1_rx,&dmamux_ReqGenParams);
/* NVIC configuration for DMAMUX request generator overrun errors*/
HAL_NVIC_SetPriority(DMAMUX2_OVR_IRQn, 0, 1);
HAL_NVIC_EnableIRQ(DMAMUX2_OVR_IRQn);
HAL_DMAEx_EnableMuxRequestGenerator (&hdma_spi1_rx);
2021-01-14 5:37 AM
The SPI is always in "HAL_SPI_STATE_BUSY_RX"
I got this with debugging tool for the DMA Handler
2021-01-14 1:54 PM
I mean the SPI and DMA peripherals (and, once you've mentioned, relevant DMAMUX) registers.
JW
2021-01-15 12:43 AM
Here is my DMA init
hdma_spi1_rx.Instance = DMA1_Stream2;
hdma_spi1_rx.Init.Request = DMA_REQUEST_SPI1_RX;
hdma_spi1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_spi1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi1_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi1_rx.Init.Mode = DMA_NORMAL;
hdma_spi1_rx.Init.Priority = DMA_PRIORITY_LOW;
hdma_spi1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_spi1_rx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(hspi,hdmarx,hdma_spi1_rx);
/* SPI1 interrupt Init */
HAL_NVIC_SetPriority(SPI1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(SPI1_IRQn);And my SPI init
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 0x0;
hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
hspi1.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
hspi1.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
hspi1.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
hspi1.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
hspi1.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
hspi1.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
hspi1.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
hspi1.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
hspi1.Init.IOSwap = SPI_IO_SWAP_DISABLE;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
Error_Handler();
}
2021-01-15 2:00 AM
I'm not really interested in source code, I don't use Cube and don't quite understand it.
Read out the registers' content.
JW
2021-01-15 2:34 AM
Sorry, I get it now. I looked register value with debugger tool at the end of the init function:
SP1 :
CR1 = 0x 0000 1000
CR2 = 0
CFG1 = 0x 7000 0007
CFG2 = 0x 0540 0000
IER = 0
SR = 0x 0000 1002
IFCR = 0
TXDR = 0
RXDR = 0
UDRDR = 0
I2SCFGR = 0I got it from this :
Here is what i got for DMA :
// DMA
CR = 0x 0000 0400
FCR = 0x 0000 0020
// DMAMUX
CR = 0x 0000 0025Do you think I should stop using Cube and just go with the datasheet ?
Thank you,
Gabriel
2021-01-15 7:37 AM
I added my own "Bare Metal" register values :
#define DMAMUX_SPI1_RX_ID 37U
void SPI1_DMA1_DMAMUX_MDMA_init (void)
{
//----Shutdown
SPI1->CR1 = 0;
DMAMUX1_Channel2->CCR = 0;
DMA1_Stream2->CR = 0;
MDMA_Channel2->CCR = 0;
//------DMA1 Stream 2----
// Configuration Register
DMA1_Stream2->CR = DMA_SxCR_CIRC | DMA_SxCR_PL_0 | DMA_SxCR_PL_1 | DMA_SxCR_MINC | DMA_SxCR_TCIE;
// Fifo control register
DMA1_Stream2->FCR = 0;
// Peripheral address register
DMA1_Stream2->PAR = (uint32_t)&(SPI1->RXDR);
// Memory address
DMA1_Stream2->M0AR = (uint32_t)&(SPI1_RxBuffer[0]);
// Second buffer in case of double buffer
DMA1_Stream2->M1AR = 0;
// Number of data items to transfer NDTR*PSIZE
DMA1_Stream2->NDTR = READBACK_LENGTH;
// Clear interrupt registers
DMA1->LISR = 0x0F7D;
DMA1->HISR = 0x0F7D;
DMA1->LIFCR = 0x0F7D;
DMA1->HIFCR = 0x0F7D;
//------DMAMUX1 Channel 2----
// Configuration Register
DMAMUX1_Channel2->CCR = DMAMUX_CxCR_EGE | DMAMUX_SPI1_RX_ID;
// Request Generator Configuration Register
DMAMUX1_RequestGenerator2->RGCR = DMAMUX_RGxCR_GE | DMAMUX_RGxCR_GPOL_0 | 2U;
// Clear interrupt registers
DMAMUX1_ChannelStatus->CFR = 0x0000FFFF;
DMAMUX1_RequestGenStatus->RGSR = 0x000000FF;
DMAMUX1_RequestGenStatus->RGCFR = 0x000000FF;
//------MDMA Channel 2----
// Config Registers
MDMA_Channel2->CCR = MDMA_CCR_PL_1 | MDMA_CCR_PL_0 | MDMA_CCR_TCIE | MDMA_CCR_CTCIE;
MDMA_Channel2->CTCR = ((READBACK_LENGTH-1)CSAR = (uint32_t)&(SPI1_RxBuffer[0]);
MDMA_Channel2->CDAR = (uint32_t)&(ads_buf[0]);
MDMA_Channel2->CTBR = MDMA_CTBR_SBUS | MDMA_CTBR_SBUS | 2;
// Clear interrupt
MDMA_Channel2->CIFCR = 0x0000001F;
// Configuration Register
// Clear interrupt registers
DMAMUX1_ChannelStatus->CFR = 0x0000FFFF;
DMAMUX1_RequestGenStatus->RGSR = 0x000000FF;
DMAMUX1_RequestGenStatus->RGCFR = 0x000000FF;
//------SP1------
// Configuration Registers
SPI1->CR2 = (1<<16U) | READBACK_LENGTH;
SPI1->CFG1 = (0x01110000) | SPI_CFG1_RXDMAEN;
SPI1->CFG2 = SPI_CFG2_AFCNTR | SPI_CFG2_SSOE | SPI_CFG2_CPHA | SPI_CFG2_MASTER;
SPI1->I2SCFGR = 0;
// Clear interrupt registers
SPI1->IFCR = 0x00000FF4;
//Start Peripherals
MDMA_Channel2->CCR |= MDMA_CCR_EN;
DMAMUX1_Channel2->CCR |= DMAMUX_CxCR_EGE;
DMA1_Stream2->CR |= DMA_SxCR_EN;
SPI1->CR1 = SPI_CR1_SPE;
}But the chronogram is still the exact same I posted before
2021-01-15 3:39 PM
This appears to be much more complicated than I thought. I don't use the H7 and I realized that the SPI in there is much more different from other STM32 than I thought, and I don't understand how Rx-only on this SPI is supposed to work. It appears to me that there's no such mode in this SPI.
In other STM32, once you set Rx-only mode and set SPE, it automatically starts to generate clocks. Here, it appears, that you are supposed to Tx to be able to generate clocks.
JW
We’re moving the ST Community to a new platform to give you a better and more reliable community experience.