Hi there,
first of all, thanks for the useful information in this forum. You already helped me a lot for my first steps with the STM32F4 discovery board.
I set up SPI with an external ADC using DMA.
The STM32F4 is the SPI master.
SPI_Enable/Disable is triggered by an external interrupt.
DMA is working, when using a single buffer.
Here's the problem:
I now try to use the DMA double buffer mode, but it doesn't work as expected. As far as I understood from some posts and the manual, the active buffer should be switched automatically when the transfer complete flag is set. But in my case this does not happen.
For test purpose I make debug output in
DMA1_Stream3_IRQHandler (see below)
expecting the terminal to show alternating "*.*.*.", but in effect, I only get "*******" and only aRxBuffer[0] receives the data, whereas aRxBuffer[1] stays unaffected.
I don't see why. Can you help, please?
Kind regards,
Roland
Here is part of the code:
//##############
// used makros
//##############
#define SPIadc SPI2
#define SPIadc_IRQn SPI2_IRQn
#define SPIadc_IRQHANDLER SPI2_IRQHandler
#define SPIadc_SCK_PIN GPIO_Pin_10
#define SPIadc_SCK_GPIO_PORT GPIOB
#define SPIadc_SCK_GPIO_CLK RCC_AHB1Periph_GPIOB
#define SPIadc_SCK_SOURCE GPIO_PinSource10
#define SPIadc_SCK_AF GPIO_AF_SPI2
#define SPIadc_MISO_PIN GPIO_Pin_14
#define SPIadc_MISO_GPIO_PORT GPIOB
#define SPIadc_MISO_GPIO_CLK RCC_AHB1Periph_GPIOB
#define SPIadc_MISO_SOURCE GPIO_PinSource14
#define SPIadc_MISO_AF GPIO_AF_SPI2
#define SPIadc_DMA DMA1
#define SPIadc_DMA_CLK RCC_AHB1Periph_DMA1
#define SPIadc_RX_DMA_CHANNEL DMA_Channel_0
#define SPIadc_RX_DMA_STREAM DMA1_Stream3
#define SPIadc_RX_DMA_FLAG_TCIF DMA_FLAG_TCIF3
#define SPIadc_DMA_IRQn DMA1_Stream3_IRQn
//!Input to STM32
#define ADC_AD7665_BUSY_PIN GPIO_Pin_5
#define ADC_AD7665_BUSY_PORT GPIOE
#define ADC_AD7665_BUSY_CLK RCC_AHB1Periph_GPIOE
#define EXTI9_5_Enable NVIC_EnableIRQ(EXTI9_5_IRQn)
#define EXTI9_5_Disable NVIC_DisableIRQ(EXTI9_5_IRQn)
//##############
// global variable
//##############
__IO uint16_t aRxBuffer[2][BUFFERSIZE];
//##############
// SPI & DMA Configuration
//##############
GPIO_InitTypeDef GPIO_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* Peripheral Clock Enable -------------------------------------------------*/
/* Enable the SPI clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
/* Enable GPIO clocks */
RCC_AHB1PeriphClockCmd(SPIadc_SCK_GPIO_CLK | SPIadc_MISO_GPIO_CLK, ENABLE);
/* Enable DMA clock */
RCC_AHB1PeriphClockCmd(SPIadc_DMA_CLK, ENABLE);
/* SPI GPIO Configuration --------------------------------------------------*/
/* Connect SPI pins to AF5 */
GPIO_PinAFConfig(SPIadc_SCK_GPIO_PORT, SPIadc_SCK_SOURCE, SPIadc_SCK_AF);
GPIO_PinAFConfig(SPIadc_MISO_GPIO_PORT, SPIadc_MISO_SOURCE, SPIadc_MISO_AF);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
/* SPI SCK pin configuration */
GPIO_InitStructure.GPIO_Pin = SPIadc_SCK_PIN;
GPIO_Init(SPIadc_SCK_GPIO_PORT, &GPIO_InitStructure);
/* SPI MISO pin configuration */
GPIO_InitStructure.GPIO_Pin = SPIadc_MISO_PIN;
GPIO_Init(SPIadc_MISO_GPIO_PORT, &GPIO_InitStructure);
/* SPI configuration -------------------------------------------------------*/
SPI_I2S_DeInit(SPIadc);
SPI_StructInit(&SPI_InitStructure);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_RxOnly;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
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_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_Init(SPIadc, &SPI_InitStructure);
//! DMA configuration
//! Deinitialize DMA Streams
DMA_DeInit(SPIadc_RX_DMA_STREAM);
//! Configure DMA Initialization Structure
DMA_StructInit(&DMA_InitStructure);
DMA_InitStructure.DMA_BufferSize = BUFFERSIZE ;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable ;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull ;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single ;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) (&(SPIadc->DR)) ;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
//! Configure RX DMA
DMA_InitStructure.DMA_Channel = SPIadc_RX_DMA_CHANNEL ;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory ;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&aRxBuffer[0] ;
DMA_Init(SPIadc_RX_DMA_STREAM, &DMA_InitStructure);
//! Configure DMA Double Buffer
DMA_DoubleBufferModeConfig(SPIadc_RX_DMA_CHANNEL, (uint32_t)&aRxBuffer[1], DMA_Memory_0);
DMA_DoubleBufferModeCmd(SPIadc_RX_DMA_CHANNEL, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = SPIadc_DMA_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//! Enable the GPIO for ADC_AD7665_BUSY signal
RCC_AHB1PeriphClockCmd(ADC_AD7665_BUSY_CLK, ENABLE);
GPIO_InitStructure.GPIO_Pin = ADC_AD7665_BUSY_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(ADC_AD7665_BUSY_PORT, &GPIO_InitStructure);
//##############
// startup inside main:
//##############
//!SPIadc will be enabled by some interrupt
SPI_Cmd(SPIadc, DISABLE);
//!Enable DMA Rx Stream for SPIadc
DMA_Cmd(SPIadc_RX_DMA_STREAM,ENABLE);
//!Enable DMA transfer complete interrupt
DMA_ITConfig(DMA1_Stream3, DMA_IT_TC, ENABLE);
//!Enable SPIadc DMA Rx Request
SPI_I2S_DMACmd(SPIadc, SPI_I2S_DMAReq_Rx, ENABLE);
if(DMA_GetCmdStatus == DISABLE)
{
printf("DMA_GetCmdStatus = DISABLED \n\r");
while(DMA_GetCmdStatus == DISABLE)
{/*wait for the stream to be enabled */;}
}
printf("DMA_GetCmdStatus = ENABLED \n\r");
//##############
// DMA transfer complete interrupt:
//##############
void DMA1_Stream3_IRQHandler(void)
{
if (DMA_GetITStatus(DMA1_Stream3, DMA_FLAG_TCIF3) == RESET)
{
STM_EVAL_LEDToggle(LED3);
EXTI9_5_Disable;
DMA_ClearFlag(DMA1_Stream3, DMA_FLAG_TCIF3);
DMA_ClearITPendingBit(DMA1_Stream3, DMA_IT_TCIF3);
if (DMA_GetCurrentMemoryTarget(DMA1_Stream3) == 0)
{
printf("*");
// always ends up here
}
else
{
printf(".");
// never gets here
}
EXTI9_5_Enable;
}
}