I have STM32F4407VGT6 controller on board STM32F4 Discovery. I try to read data from the AD7683 ADC using SPI + DMA, but the DMA receive buffer is always empty (all zeroes). In polled mode, everything works fine, but i must read one 16-bit sample value as 3x 8-bit SPI value and use a bit shifts. That is perhaps the problem. My sampling frequency is 48 kHz and and during each period must be read three spi values to get one ADC sample.
AD7683 timing diagram is in datasheet, page 5.
SPI comunication on pins is fine. Here is screen from analyzer: pic
Does anyone know how to solve this, or where the problem is ?
Thanks in advance.
Here is my code:
#define DMAbufferSizeRx 3
__IO uint8_t DMAbufferRx[DMAbufferSizeRx];
#define DMAbufferSizeTx 1
__IO uint8_t DMAbufferTx[DMAbufferSizeTx] ;
void DMAconfig(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the DMA Stream IRQ Channel */
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
DMA_InitTypeDef DMA_InitStructure;
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_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(SPI3->DR));
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
// Configure Tx DMA
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) &DMAbufferTx[0];
DMA_InitStructure.DMA_BufferSize = DMAbufferSizeTx;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
DMA_Cmd(DMA1_Stream5, DISABLE);
while (DMA1_Stream5->CR & DMA_SxCR_EN);
DMA_Init(DMA1_Stream5, &DMA_InitStructure);
/* Configure Rx DMA */
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) &DMAbufferRx[0];
DMA_InitStructure.DMA_BufferSize = DMAbufferSizeRx;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_Cmd(DMA1_Stream0, DISABLE);
while (DMA1_Stream0->CR & DMA_SxCR_EN);
DMA_Init(DMA1_Stream0, &DMA_InitStructure);
DMA_ITConfig(DMA1_Stream0, DMA_IT_TC , ENABLE); //| DMA_IT_HT
/* Enable the DMA channel */
DMA_ClearFlag(DMA1_Stream0, DMA_FLAG_FEIF0|DMA_FLAG_DMEIF0|DMA_FLAG_TEIF0|DMA_FLAG_HTIF0|DMA_FLAG_TCIF0);
DMA_ClearFlag(DMA1_Stream5, DMA_FLAG_FEIF5|DMA_FLAG_DMEIF5|DMA_FLAG_TEIF5|DMA_FLAG_HTIF5|DMA_FLAG_TCIF5);
DMA_Cmd(DMA1_Stream0, ENABLE); // Enable the DMA SPI TX Stream
DMA_Cmd(DMA1_Stream5, ENABLE); // Enable the DMA SPI RX Stream
// Enable the SPI Rx/Tx DMA request
SPI_I2S_DMACmd(SPI3, SPI_I2S_DMAReq_Rx, ENABLE);
SPI_I2S_DMACmd(SPI3, SPI_I2S_DMAReq_Tx, ENABLE);
SPI_Cmd(SPI3, ENABLE);
}
void DMA1_Stream0_IRQHandler(void)
{
/* Test on DMA Stream Transfer Complete interrupt */
if(DMA_GetITStatus(DMA1_Stream0, DMA_IT_TCIF0))
{
/* Clear DMA Stream Transfer Complete interrupt pending bit */
DMA_ClearITPendingBit(DMA1_Stream0, DMA_IT_TCIF0);
// here is buffer still empty....
}
}
void SPIconfig()
{
SPI_InitTypeDef SPI_InitStructure;
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_DataSize = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft | SPI_NSSInternalSoft_Set;
SPI_InitStructure.SPI_BaudRatePrescaler =SPI_BaudRatePrescaler_16;
SPI_InitStructure.SPI_CRCPolynomial = 0;
SPI_Init(SPI3, &SPI_InitStructure);
SPI_CalculateCRC(SPI3, DISABLE);
SPI_Cmd(SPI3,ENABLE);
}
void RCCenable(void)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOH, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);
RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_DMA1, ENABLE);
}
void GPIOconfig(void)
{
GPIO_InitTypeDef GPIO_InitDef;
GPIO_InitDef.GPIO_Pin = REG_ON_OFF | ADC_DRIVER_ON_OFF | GPIO_Pin_6;
GPIO_InitDef.GPIO_OType = GPIO_OType_PP;
GPIO_InitDef.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitDef.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitDef.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_Init(GPIOE, &GPIO_InitDef);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = SDATA | MOSI | SCLK;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_SPI3);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource4, GPIO_AF_SPI3);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_SPI3);
GPIO_InitStructure.GPIO_Pin = CS;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_SetBits(GPIOD,CS);
}
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
GPIO_ToggleBits(GPIOD,CS);
}
}
void TIM2_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseStructure.TIM_Period = 875;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM2, ENABLE);
}
Looks like you initialize your DMA_Mode
, DMA_MemoryDataSize
and DMA_MemoryInc
fields twice. It is useless - only last remark is saved.
Also your DMA_PeripheralDataSize
does not match DMA_MemoryDataSize
when it should.
You didn't attach main function, so i can't see init functions call order. DMAconfig()
has to be called earlier than SPIconfig()
.
There is next error at SPIconfig
:
1) I think you guess, what you have to correct.
SPI_InitStructure.SPI_DataSize = SPI_FirstBit_MSB;
2) Change
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft |
SPI_NSSInternalSoft_Set;
to
SPI_init.SPI_NSS = SPI_NSS_Soft;
And end up initializing like this:
SPI_Init(SPI3, &SPI_init);
SPI_SSOutputCmd(SPI3, ENABLE); //!!!!
SPI_Cmd(SPI3, ENABLE);
SPI_NSSInternalSoftwareConfig(SPI3, SPI_NSSInternalSoft_Set); //!!!!
SPI_I2S_DMACmd(SPI3, SPI_I2S_DMAReq_Tx, ENABLE);
Hope it will help if you haven't solved your problem yet.