cancel
Showing results for 
Search instead for 
Did you mean: 

Spi dma: can't change spi prescale

teijo
Associate II
Posted on January 16, 2017 at 16:10

Hi,

I'm trying to get spi driver working for ad-converter. Adc spi is supporting ~20mhz spi clock. Now my project APB2(Using spi1) clock is 84 Mhz and spi prescale is now 2( Spi clock is 42Mhz) and code is running fine, but some samples is corrupted, so i assumed that the problem is that spi clock is too high(). Problem is when i change prescale to 4 it's get stuck to loop which check if spi running. This code is required call every time dma is complete.

static void stopReceiving()

{

    SPI_Cmd(SPI1, DISABLE);

    while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET); // STUCK HERE

    SPI_I2S_ReceiveData(SPI1);

2 REPLIES 2
S.Ma
Principal
Posted on January 16, 2017 at 18:24

Try not to disable SPI. Busy flag tells when the SPI is at rest and its configuration changed (and disabled). Remember that writing a byte for transmit will generate spi clocks, and RXNE will tell when all the clocks have been expelled onto the bus and the slave byte is ready for reading. Any details on which STM32, which SPI mode is used to better understand the context?

When using DMA, configure and activate DMA RX before setting up and activate DMA TX... Or the clock will kick in too early. Also use DMA RX interrupt, not DMA TX one. 

teijo
Associate II
Posted on January 17, 2017 at 10:54

Hello

I managed to change the APB2 clock 42 MHz. But the it did not solve my problem. I have been using this code SPI-driver for our project for a few years. Now I wanted to try the CUBE and implemented the old SPI-driver to new CUBE code. For some reason I get errors in my adc-values.

The basic function is that I trigger SPI-DMA transfer triggered by ADC-dataready. After pin change STM-IRQ starts DMA transfer. After transfer is done (approx 10 us) stopReceiving() is called. This loop stat over when new ADC-dataready is received. This is working in my old code but new implemention to CUBE seems to generate false values in ADC data.

Ideas where to look? Seems like this could be related to IRQ and timing issues.

The reason for using old SPI-driver is that  CUBE documentation stated some SPI speed limitations (2lines RXOnly, master -> FPCLK/64).

Below is SPI and DMA initialization. I'm using STM32F407

static void initSpiHW()

{

NVIC_InitTypeDef NVIC_InitStructure;

SPI_InitTypeDef SPI_InitStructure;

/* SPI initialization */

SPI_I2S_DeInit(SPI1);

SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_RxOnly;

SPI_InitStructure.SPI_Mode = SPI_Mode_Master;

SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;

SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;

SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;

SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;

SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;

SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;

SPI_InitStructure.SPI_CRCPolynomial = 7;

SPI_Init(SPI1, &SPI_InitStructure);

/* Configure the SPI interrupt priority */

NVIC_InitStructure.NVIC_IRQChannel = SPI1_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

/* Enable DMA requests */

SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, ENABLE);

}

static void initDMAHW()

{

DMA_InitTypeDef DMA_InitStructure;

NVIC_InitTypeDef NVIC_InitStructure;

DMA_DeInit(DMA2_Stream0);

DMA_StructInit(&DMA_InitStructure);

DMA_InitStructure.DMA_Channel = DMA_Channel_3;

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;

DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;//DMA_Priority_High;//

DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;

DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;

DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_INC8;//DMA_MemoryBurst_Single;//

DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(SPI1->DR);

DMA_Init(DMA2_Stream0, &DMA_InitStructure);

// DMA generates interrupt on DMA transfer complete and on errors failed

DMA_ITConfig(DMA2_Stream0, DMA_IT_TC | DMA_IT_TE | DMA_IT_DME, ENABLE);

// Peripheral flow control

DMA_FlowControllerConfig(DMA2_Stream0, DMA_FlowCtrl_Memory);

// Transfer size

DMA_SetCurrDataCounter(DMA2_Stream0, ADS1278_BLOCK_SIZE);

// Enable interrupt for this channel

NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = ADC_SPI_DMA_INTERRUPT_PRIORITY;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = ADC_SPI_DMA_INTERRUPT_PRIORITY;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

}