cancel
Showing results for 
Search instead for 
Did you mean: 

SPI Rx buffer not reading

Arno Thiele
Associate III
Posted on August 30, 2017 at 15:24

Hello,

I am trying to get my MCP3204 ADC to run with my STM32F4. Unfortunately all I get from my SPI_I2S_ReceiveData() function is a bunch of zeros. According to my oscilloscope everything looks normal. I am getting a clock signal, a MOSI transmission to the ADC that looks normal and is in the right range, the chip select signal looks fine and the ADC is answering with what looks like a word that reacts accurately to potentiometer movement. But my STM32F4 just won’t read anything from the SPI4->DR register.

I also tried a simple loopback test connecting MISO and MOSI. The result is the same. All signals look normal on my scope, all the flags are set and cleared, all clocks are running but the SPI read register still appears empty. I also tried the same on SPI2 with the same negative result.

Also I can assure that the problem is not with the <*pitchP>pointer or anything down stream, since it works just fine if I replace <value> with any constant integer value.

Unfortunately I don’t have a multi channel scope or logic analyzer to look at the timing at the pins but the code for the send/receive procedure I am using is very basic and by the book and it works in countless other projects.

Any help is much appreciated!

void init_Clocks(void)
{
 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_DMA2, ENABLE); // maybe try DMA for ADC at some point
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 | RCC_APB2Periph_SPI4 | RCC_APB2Periph_ADC1, ENABLE); // SPI1 Clock - DAC, SPI4 Clock - ADC, ADC1 Clock
 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // TIM2 Timer - Clock prescale 2
}
void init_ADC_ext (void)
{
 // Initialize CS pin.
 GPIO_InitTypeDef gpio_init;
 gpio_init.GPIO_Pin = GPIO_Pin_12;
 gpio_init.GPIO_Speed = GPIO_Fast_Speed;
 gpio_init.GPIO_Mode = GPIO_Mode_OUT;
 gpio_init.GPIO_OType = GPIO_OType_PP;
 gpio_init.GPIO_PuPd = GPIO_PuPd_NOPULL;
 GPIO_Init(GPIOB, &gpio_init);
 // Initialize CLK pin.
 gpio_init.GPIO_Pin = GPIO_Pin_13;
 gpio_init.GPIO_Speed = GPIO_Fast_Speed;
 gpio_init.GPIO_Mode = GPIO_Mode_AF;
 gpio_init.GPIO_OType = GPIO_OType_PP;
 gpio_init.GPIO_PuPd = GPIO_PuPd_NOPULL;
 GPIO_Init(GPIOB, &gpio_init);
 // Initialize MOSI pin.
 gpio_init.GPIO_Pin = GPIO_Pin_1;
 gpio_init.GPIO_Speed = GPIO_Fast_Speed;
 gpio_init.GPIO_Mode = GPIO_Mode_AF; 
 gpio_init.GPIO_OType = GPIO_OType_PP;
 gpio_init.GPIO_PuPd = GPIO_PuPd_NOPULL;
 GPIO_Init(GPIOA, &gpio_init);
 // Initialize MISO pin. This one is not receiving anything.
 gpio_init.GPIO_Pin = GPIO_Pin_11;
 gpio_init.GPIO_Speed = GPIO_Fast_Speed;
 gpio_init.GPIO_Mode = GPIO_Mode_IN; // MISO must be configured as HI-Z IN, not AF!!
// gpio_init.GPIO_OType = GPIO_OType_PP;
 gpio_init.GPIO_PuPd = GPIO_PuPd_NOPULL;
 GPIO_Init(GPIOA, &gpio_init);
 // Initialize SPI
 SPI_InitTypeDef spi_init;
 spi_init.SPI_Direction = SPI_Direction_2Lines_FullDuplex; 
 spi_init.SPI_Mode = SPI_Mode_Master;
 spi_init.SPI_DataSize = SPI_DataSize_16b; // SPI_DataSize_8b for ADCread() 
 spi_init.SPI_CPOL = SPI_CPOL_Low;
 spi_init.SPI_CPHA = SPI_CPHA_1Edge;
 spi_init.SPI_NSS = SPI_NSS_Soft;
 spi_init.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; // Prescaler_64 for ADCread()
 spi_init.SPI_FirstBit = SPI_FirstBit_MSB;
 spi_init.SPI_CRCPolynomial = 7;
 SPI_Init(SPI4, &spi_init);
// GPIO_SetBits(GPIOB, GPIO_Pin_12);
 SPI_Cmd(SPI4, ENABLE);
 GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_SPI4);
 GPIO_PinAFConfig(GPIOA, GPIO_PinSource11, GPIO_AF_SPI4);
 GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF6_SPI4);
}

void loopback(void){
 uint16_t value = 0;
 while (SPI_I2S_GetFlagStatus(SPI4, SPI_I2S_FLAG_TXE) == RESET);
 SPI_I2S_SendData(SPI4, 440);
 while (SPI_I2S_GetFlagStatus(SPI4, SPI_I2S_FLAG_RXNE) == RESET);
 value = SPI_I2S_ReceiveData(SPI4);
 *pitchP = value;
}
void ADCread(void){
 
 uint16_t value = 0;
 GPIO_ResetBits(GPIOB, GPIO_Pin_12);
 // Send header
 while (SPI_I2S_GetFlagStatus(SPI4, SPI_I2S_FLAG_TXE) == RESET);
 SPI_I2S_SendData(SPI4, 0b00000110); // or 0x04 | 0x02 
 while (SPI_I2S_GetFlagStatus(SPI4, SPI_I2S_FLAG_RXNE) == RESET);
 SPI_I2S_ReceiveData(SPI4);
 // Send channel / receive first part
 while (SPI_I2S_GetFlagStatus(SPI4, SPI_I2S_FLAG_TXE) == RESET);
 SPI_I2S_SendData(SPI4, 0b00000000); // 0b01000000 for the other channel
 while (SPI_I2S_GetFlagStatus(SPI4, SPI_I2S_FLAG_RXNE) == RESET);
 value = (SPI_I2S_ReceiveData(SPI4) & 0xf) << 8; 
 
 // Send trailing word / receive second part
 while (SPI_I2S_GetFlagStatus(SPI4, SPI_I2S_FLAG_TXE) == RESET);
 SPI_I2S_SendData(SPI4, 0x00);
 while (SPI_I2S_GetFlagStatus(SPI4, SPI_I2S_FLAG_RXNE) == RESET);
 value |= SPI_I2S_ReceiveData(SPI4);
 GPIO_SetBits(GPIOB, GPIO_Pin_12);
 *pitchP = value;
}

int main (){
SystemInit();
init_Clocks();
init_ADC_ext();
while(1) {
Loopback(); 
ADCread();
}
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

4 REPLIES 4
Posted on August 30, 2017 at 21:36

Hello!

At your initialization code >>

 gpio_init.GPIO_Mode = GPIO_Mode_IN; // MISO must be configured as HI-Z IN, not AF!!
But after you try to read the SPI DR 
Is this your intention?
Regards 
vf

Arno Thiele
Associate III
Posted on August 30, 2017 at 23:08

Thanks for your reply! I just found the solution: 

In line 43/44/45 I am configuring the SPI pins for the corresponding alternative function. I missed something when I looked up the pins in the alternative function chart: Pin A 11 must be mapped to AF6 for the SPI4 MISO function, but the second argument <GPIO_AF_SPI4> by default maps it to AF5. So I changed the second argument to

<GPIO_AF6_SPI4> and n

ow it works perfectly fine!

You mention my comment in the GPIO initialisation code. It is correct that the pin has to be configured as INPUT, not as AF. That is for the external ADC to work correctly. It won't work if the pin is configured as AF. But If I do the loopback test shorting MISO and MOSI it's the other way round. For the test to work the pin has to be initialised as AF, not as INPUT. Why that is I have no clue.

Mikas Longbardi
Associate II
Posted on August 31, 2017 at 01:39

MISO must be configurated in MISO mode(AF).

>>> gpio_init.GPIO_Mode = GPIO_Mode_IN; // MISO must be configured as HI-Z IN, not AF!!

Posted on August 31, 2017 at 19:07

That is actually not correct. See my post above. The pin has to be mapped to AF6 (line 44), but the corresponding GPIO has to be initialised as INPUT for things to work, not as AF. The line you quoted works fine.