2017-08-30 06:24 AM
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();
}
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
2017-08-30 12:36 PM
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
2017-08-30 02:08 PM
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.
2017-08-30 04:39 PM
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!!
2017-08-31 12:07 PM
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.