# Setting up SPI between a STM32F4-Discovery Board and a MCP4151 Digital Pot

I'm currently working on a project in which I'm trying to interface a MCP4151 Digital Potentiometer with the STM32F4-Discovery Board using the Mars Eclipse IDE. I have downloaded and included the STM32F4xx HAL but am struggling in getting all the pins and setting right.

From the STM32F407 datasheet (page 49) I was able to deduce that I want to use PA5 and PA7 as pins for SPI_SCK and SPI_MOSI. So I modified the code from this project to enable these pins:

void SPI_Init(){
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;

HAL_SPI_Init(&hspi1);
/* Peripheral clock enable */
__SPI1_CLK_ENABLE();

GPIO_InitTypeDef GPIO_InitStruct;
/**SPI1 GPIO Configuration
PA5 ------> SPI1_SCK
PA7 ------> SPI1_MOSI
*/
GPIO_InitStruct.Pin = GPIO_PIN_5 | GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

GPIO_InitStruct.Pin = GPIO_PIN_0;                //Chip Select
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

__HAL_SPI_ENABLE(&hspi1);
}


With that I try to initialize the values on the potentiometer using:

void SPI_SendData(uint8_t* adress, uint8_t* data, uint16_t size, uint32_t timeout){

HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_SET);

while(HAL_SPI_GetState(&hspi1) == HAL_SPI_STATE_BUSY);

HAL_SPI_Transmit(&hspi1, data, size, timeout);
while(HAL_SPI_GetState(&hspi1) == HAL_SPI_STATE_BUSY);

HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET);
}


And then write:

void POT_Init(){
uint8_t data = 0x00;
SPI_SendData(&STATUS_REGISTER_ADDRESS, &data, 8, 100); //Set SREG bit 1 to 0. Device is NOT in shutdown.
data = 0x0F;
SPI_SendData(&TCON_BIT_REGISTER_ADDRESS, &data, 8, 100); //Connect Wiper 0
data = 0x08;
}


Problem is, I'm probing SCK and SDI/PA5 and PA7 and am not seeing anything move across the line. The two devices are connected as below:

So why am I not seeing anything? I'm assuming something is missing in my Init function but I can't put my finger on it and I'd appreciate a second look.

I am not sure is this helps any more given how old this post is. However, I noticed that you are setting PA5 and PA7 as Alternate Function, but not actually specifying which Alternate function through a GPIO_InitStruct.Alternate assignment.

Firstly, you must enable the clock to the SPI peripheral before you attempt to initialise it. Secondly, have you also enabled the clock to the GPIO peripherals?

(I've only used STM32F103, which admittedly might be a little different but I doubt it)

• +1, Indeed __GPIOA_CLK_ENABLE(); and __GPIOC_CLK_ENABLE(); calls are missing. Dec 9, 2015 at 13:01
• You were correct, and @Bence had the correct function calls. I did forget to enable the GPIOA and GPIOC clocks. With that enabled I am now able to move the PC0 pin. hurrah But PA5 and PA7 are still dead in the water. Dec 9, 2015 at 18:31
• How do you check these pins? Oscilloscope or just the potentiometers output you check? Dec 9, 2015 at 18:38
• I have PC0, PA5 and PA7 hooked up to an Oscope and P0W and P0A connected to a Multimeter. Here is a picture of the setup. Ignore the Clock and Data signal, I've been experimenting with manually flipping the pins to implement my own version of SPI. I'd rather get the real version do work though. Dec 9, 2015 at 18:59
• You must still move the __SPI1_CLK_ENABLE to before HAL_SPI_Init, otherwise the SPI init will do nothing because the registers it writes to are not clocked. Dec 10, 2015 at 2:24

I found this post while searching for a similar post and saw that it has no accepted answer so I decided to write an answer (so anyone with a similar problem can hopefully find a solution).

Before using SPI there a few things you should consider:

• The max frequency of the SCLK that your device (MCP4151) is able to function with.
• The SPI mode in which your device (MCP4151) is able to function
• The timing requirements of your device (MCP4151)

Having said that there are a few things I want to mention.

First of all I see that in your void SPI_SendData(uint8_t* adress, uint8_t* data, uint16_t size, uint32_t timeout) function you set the Chip Select pin, send the address, send the data and then reset it. Usually the Chip Select Pin is active low so in order for the SPI to work you need to reset the pin and after you are done set it again.

Furthermore, you have to check the freq of the SPI clock. If your device (stm32f4) is clocked at 168MHz and you've selected SPI_BAUDRATEPRESCALER_2 that means that your SPI is clocked at 42MHz which is pretty high and I'm pretty sure that the MCP4151 cannot work at so high frequency. In order to find the maximum frequency your device is able to work you have to look in the datasheet.

Last but not least in your datasheet you have to check in which SPI mode the MCP4151 works. There are 4 different SPI modes so the mode you selected may be wrong.

P.S many devices have strict timing requirements between read and write commands of between consecutive write or read commands.

I had a trouble with SPI on STM32H7. The issue was that the clock pulses were missing. The last byte had 4-7 clock pulses instead of 8. The number of the pulses were different each transmission cycle. After investigation I found that only if SPI pins are configured with GPIO_SPEED_FREQ_LOW than this problem exists. Even with the SPI frequency down to 7 kHz. As soon as I change the GPIO frequency settings to any other (medium, high, very high) the problem disappears. I have not found yet the explanation for the issue.