cancel
Showing results for 
Search instead for 
Did you mean: 

SPI on STM32F411RE doesn't work and the Clock is not running correct

TRudn.1
Associate II

Hello,

I'm trying to connect my MPU6500 to my Nucleo f411re board with the SPI Protocol.

The MPU6500 is working correctly because I tested it with an Arduino and it worked as expected.

I'm using SPI2 with the Pins PB15, PB14 and PB13.

But for some reason I can't get it to work on the STMF411. Infact the clock isn't even working correctly as you can see on the oscilloscope.

Yellow is the Clock and Blue is MOSI. (Yellow is scaled to 500mv and Blue to 5v)

Maybe my configuration is wrong?

I hope someone could help me it and spot the mistake.

Thanks in advance!

#include "main.h"
 
#include <string.h>
#include <stdio.h>
 
//ioSpeedConfig
#define LOW_SPEED 0x00
#define MEDIUM_SPEED 0x01
#define FAST_SPEED 0x02
#define HIGH_SPEED 0x03
//ioPinConfig
#define INPUT_MODE 0x00
#define OUTPUT_MODE 0x01
#define ALTERNATIVE_MODE 0x02
#define ANALOG_MODE 0x03
//ioOtypeConfig
#define Push_Pull 0x00
#define Open_Drain 0x01
//ioPushPullConfig
#define NO_PULL 0x00
#define PULL_UP 0x01
#define PULL_DOWN 0x02
 
#define SET_PIN 1
#define RESET_PIN 0
 
#define AF0 0000 //system
#define AF1 0001 //(TIM1/TIM2)
#define AF2 0010 //(TIM3..5)
#define AF3 0011 //(TIM9..11)
#define AF4 0100 //(I2C1..3)
#define AF5 0101 //(SPI1..4)
#define AF6 0110 //(SPI3..5)
#define AF7 0111 //(USART1..2)
#define AF8 1000 //(USART6)
#define AF9 1001 //(I2C2..3)
#define AF10 1010 //(OTG_FS)
#define AF11 1011 //NOTHING?
#define AF12 1100 //(SDIO)
#define AF13 1101 //NOTHING?
#define AF14 1110 //NOTHING?
#define AF15 1111 //(EVENTOUT)
 
UART_HandleTypeDef huart2;
 
const uint8_t SPI_READ = 0x80;
const uint8_t PWR_MGMNT_1 = 0x6B;
const uint8_t PWR_RESET = 0x80;
const uint8_t WHO_AM_I = 0x75;
 
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
 
void ioPinConfig(GPIO_TypeDef *portName, uint8_t pinNum, uint8_t configValue);
void ioPinSetReset(GPIO_TypeDef *portName, uint8_t pinNum, uint8_t pinState);
void ioPinPullConfig(GPIO_TypeDef *portName, uint8_t pinNum, uint8_t configValue);
void ioPinAlternateFunConfig(GPIO_TypeDef *portName, uint8_t pinNum, uint8_t configValue);
void ioPinOTypeConfig(GPIO_TypeDef *portName, uint8_t pinNum, uint8_t configValue);
void ioPinSetReset(GPIO_TypeDef *portName, uint8_t pinNum, uint8_t pinState);
uint8_t readRegister(SPI_TypeDef *spih, uint8_t subAddress);
void writeRegister(SPI_TypeDef *spih, uint8_t subAddress, uint8_t value);
 
void ioPinConfig(GPIO_TypeDef *portName, uint8_t pinNum, uint8_t configValue)
{
  portName->MODER = (portName->MODER & (~(0b11<<((2*pinNum))))) | (configValue << (2 * pinNum));
}
 
void ioPinSpeedConfig(GPIO_TypeDef *portName, uint8_t pinNum, uint8_t configValue)
{
  portName->OSPEEDR = (portName->OSPEEDR & (~(0b11<<((2*pinNum))))) | (configValue << (2 * pinNum));
}
 
void ioPinPullConfig(GPIO_TypeDef *portName, uint8_t pinNum, uint8_t configValue)
{
  portName->PUPDR = (portName->PUPDR & (~(0b11<<((2*pinNum))))) | (configValue << (2* pinNum));
}
 
void ioPinAlternateFunConfig(GPIO_TypeDef *portName, uint8_t pinNum, uint8_t configValue)
{
  if(pinNum < 8)
    portName->AFR[0] = (portName->AFR[0] & (~(0xF<<((4*pinNum))))) | (configValue << (4 * pinNum));
  else
    portName->AFR[1] = (portName->AFR[1] & (~(0xF<<((4*(pinNum-8)))))) | (configValue << (4 * (pinNum-8)));
}
 
void ioPinOTypeConfig(GPIO_TypeDef *portName, uint8_t pinNum, uint8_t configValue)
{
  portName->OTYPER = (portName->OTYPER & (~(0x01<<pinNum))) | configValue << pinNum;
}
 
void ioPinSetReset(GPIO_TypeDef *portName, uint8_t pinNum, uint8_t pinState)
{
  if(pinState == SET_PIN)
    portName->BSRR = (1 << pinNum);
  else
    portName->BSRR = (1 << (pinNum + 16));
}
 
uint8_t readRegister(SPI_TypeDef *spih, uint8_t subAddress)
{
  spih->DR = (subAddress | SPI_READ);
  while(!(spih->SR & (SPI_SR_TXE)));
  spih->DR = 0x00; //Send Dummy Data
  while(!(spih->SR & (SPI_SR_TXE)));
  while(!(spih->SR & (SPI_SR_RXNE)));
  while(spih->SR & (SPI_SR_BSY));
  return spih->DR;
}
 
void writeRegister(SPI_TypeDef *spih, uint8_t subAddress, uint8_t value)
{
  spih->DR = subAddress;
  while(!(spih->SR & (SPI_SR_TXE)));
  spih->DR = value;
  while(!(spih->SR & (SPI_SR_TXE)));
}
 
 
int main(void)
{
 
  HAL_Init();
 
 
  SystemClock_Config();
 
  MX_GPIO_Init();
  MX_USART2_UART_Init();
 
  ioPinConfig(GPIOB, 15, ALTERNATIVE_MODE); //MOSI
  ioPinConfig(GPIOB, 14, ALTERNATIVE_MODE); //MISO
  ioPinConfig(GPIOB, 13, ALTERNATIVE_MODE); //SCK
 
  ioPinOTypeConfig(GPIOB, 15, Push_Pull);
  ioPinOTypeConfig(GPIOB, 14, Push_Pull);
  ioPinOTypeConfig(GPIOB, 13, Push_Pull);
 
  ioPinPullConfig(GPIOB, 15, PULL_UP);
  ioPinPullConfig(GPIOB, 14, PULL_UP);
  ioPinPullConfig(GPIOB, 13, PULL_UP);
 
  ioPinAlternateFunConfig(GPIOB, 15, AF5);
  ioPinAlternateFunConfig(GPIOB, 14, AF5);
  ioPinAlternateFunConfig(GPIOB, 13, AF5);
 
  ioPinSpeedConfig(GPIOB, 15, HIGH_SPEED);
  ioPinSpeedConfig(GPIOB, 14, HIGH_SPEED);
  ioPinSpeedConfig(GPIOB, 13, HIGH_SPEED);
 //ENABLE SPI2 Clock
  RCC->APB1ENR |= RCC_APB1ENR_SPI2EN;
  SPI2->CR1 = 0x00;
  SPI2->CR1 |= SPI_CR1_SSM | SPI_CR1_SSI | 0x05 << 3 | SPI_CR1_MSTR | SPI_CR1_CPOL | SPI_CR1_CPHA;
  SPI2->CR2 = 0x00;
//Enable SPE
  SPI2->CR1 |= SPI_CR1_SPE;
 
  writeRegister(SPI2, PWR_MGMNT_1, PWR_RESET);
  writeRegister(SPI2, 0x1B, 0x18);
 
  char buffer[16];
 
 
  while (1)
  {
//read WhoAmI Register to check if the device is working
    uint8_t whoAmIData = readRegister(SPI2, WHO_AM_I);
    sprintf(buffer, "WhoAmI: %d\r\n", whoAmIData);
    HAL_UART_Transmit(&huart2, buffer, strlen(buffer), HAL_MAX_DELAY);
  }
 
}
 
 
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
 
 
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
 
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 16;
  RCC_OscInitStruct.PLL.PLLN = 336;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
 
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}
 
 
static void MX_USART2_UART_Init(void)
{
 
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
 
}
 
static void MX_GPIO_Init(void)
{
 
  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
 
}
 
void Error_Handler(void)
{
 
}

0693W000001r4BmQAI.png

14 REPLIES 14

Oh I read this PIN would be optional since it's low by default but I look into that

TRudn.1
Associate II

Ok after adding toggling and adding the CS Pin the MISO line works as well and also the data which is transmitted seems to be correct. The MPU6500 should send 0x70 and on the oscilloscope it looks like this value. Nevertheless am I still receiving just 0 and I'm not sure if I configured the MISO Pin correctly or if the reading function is wrong.... Due to my mistakes I post the current code version here again. Thanks again for all your help!

Yellow: Clock, Dark Blue: CS Pin, Light Blue: MOSI, Pink: MISO

0693W000001r7YeQAI.png

#include "main.h"
 
#include <string.h>
#include <stdio.h>
 
//ioSpeedConfig
#define LOW_SPEED 0x00
#define MEDIUM_SPEED 0x01
#define FAST_SPEED 0x02
#define HIGH_SPEED 0x03
//ioPinConfig
#define INPUT_MODE 0x00
#define OUTPUT_MODE 0x01
#define ALTERNATIVE_MODE 0x02
#define ANALOG_MODE 0x03
//ioOtypeConfig
#define Push_Pull 0x00
#define Open_Drain 0x01
//ioPushPullConfig
#define NO_PULL 0x00
#define PULL_UP 0x01
#define PULL_DOWN 0x02
 
#define SET_PIN 1
#define RESET_PIN 0
 
#define AF0 0x0 //system
#define AF1 0x1 //(TIM1/TIM2)
#define AF2 0x2 //(TIM3..5)
#define AF3 0x3 //(TIM9..11)
#define AF4 0x4 //(I2C1..3)
#define AF5 0x5 //(SPI1..4)
#define AF6 0x6 //(SPI3..5)
#define AF7 0x7 //(USART1..2)
#define AF8 0x8 //(USART6)
#define AF9 0x9 //(I2C2..3)
#define AF10 0xA //(OTG_FS)
#define AF11 0xB //NOTHING?
#define AF12 0xC //(SDIO)
#define AF13 0xD //NOTHING?
#define AF14 0xE //NOTHING?
#define AF15 0xF //(EVENTOUT)
 
UART_HandleTypeDef huart2;
 
 
const uint8_t SPI_READ = 0x80;
const uint8_t PWR_MGMNT_1 = 0x6B;
const uint8_t PWR_RESET = 0x80;
const uint8_t WHO_AM_I = 0x75;
 
 
 
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
 
void ioPinConfig(GPIO_TypeDef *portName, uint8_t pinNum, uint8_t configValue);
void ioPinSetReset(GPIO_TypeDef *portName, uint8_t pinNum, uint8_t pinState);
void ioPinPullConfig(GPIO_TypeDef *portName, uint8_t pinNum, uint8_t configValue);
void ioPinAlternateFunConfig(GPIO_TypeDef *portName, uint8_t pinNum, uint8_t configValue);
void ioPinOTypeConfig(GPIO_TypeDef *portName, uint8_t pinNum, uint8_t configValue);
void ioPinSetReset(GPIO_TypeDef *portName, uint8_t pinNum, uint8_t pinState);
uint8_t readRegister(SPI_TypeDef *spih, uint8_t subAddress);
void writeRegister(SPI_TypeDef *spih, uint8_t subAddress, uint8_t value);
 
void ioPinConfig(GPIO_TypeDef *portName, uint8_t pinNum, uint8_t configValue)
{
  portName->MODER = (portName->MODER & (~(0b11<<((2*pinNum))))) | (configValue << (2 * pinNum));
}
 
void ioPinSpeedConfig(GPIO_TypeDef *portName, uint8_t pinNum, uint8_t configValue)
{
  portName->OSPEEDR = (portName->OSPEEDR & (~(0b11<<((2*pinNum))))) | (configValue << (2 * pinNum));
}
 
void ioPinPullConfig(GPIO_TypeDef *portName, uint8_t pinNum, uint8_t configValue)
{
  portName->PUPDR = (portName->PUPDR & (~(0b11<<((2*pinNum))))) | (configValue << (2* pinNum));
}
 
void ioPinAlternateFunConfig(GPIO_TypeDef *portName, uint8_t pinNum, uint8_t configValue)
{
  if(pinNum < 8)
    portName->AFR[0] = (portName->AFR[0] & (~(0xF<<((4*pinNum))))) | (configValue << (4 * pinNum));
  else
    portName->AFR[1] = (portName->AFR[1] & (~(0xF<<((4*(pinNum-8)))))) | (configValue << (4 * (pinNum-8)));
}
 
void ioPinOTypeConfig(GPIO_TypeDef *portName, uint8_t pinNum, uint8_t configValue)
{
  portName->OTYPER = (portName->OTYPER & (~(0x01<<pinNum))) | configValue << pinNum;
}
 
void ioPinSetReset(GPIO_TypeDef *portName, uint8_t pinNum, uint8_t pinState)
{
  if(pinState == SET_PIN)
    portName->BSRR = (1 << pinNum);
  else
    portName->BSRR = (1 << (pinNum + 16));
}
 
uint8_t readRegister(SPI_TypeDef *spih, uint8_t subAddress)
{
  ioPinSetReset(GPIOB, 10, RESET_PIN);
  spih->DR = (subAddress | SPI_READ);
  while(!(spih->SR & (SPI_SR_TXE)));
  spih->DR = 0x00;
  while(!(spih->SR & (SPI_SR_TXE)));
  while(!(spih->SR & (SPI_SR_RXNE)));
  while(spih->SR & (SPI_SR_BSY));
  ioPinSetReset(GPIOB, 10, SET_PIN);
  return spih->DR;
}
 
void writeRegister(SPI_TypeDef *spih, uint8_t subAddress, uint8_t value)
{
  ioPinSetReset(GPIOB, 10, RESET_PIN);
  spih->DR = subAddress;
  while(!(spih->SR & (SPI_SR_TXE)));
  spih->DR = value;
  while(!(spih->SR & (SPI_SR_TXE)));
  ioPinSetReset(GPIOB, 10, SET_PIN);
}
 
 
int main(void)
{
 
  HAL_Init();
 
  SystemClock_Config();
 
  MX_GPIO_Init();
  MX_USART2_UART_Init();
 
 
  ioPinConfig(GPIOB, 15, ALTERNATIVE_MODE); //MOSI
  ioPinConfig(GPIOB, 14, ALTERNATIVE_MODE); //MISO
  ioPinConfig(GPIOB, 13, ALTERNATIVE_MODE); //SCK
  ioPinConfig(GPIOB, 10, OUTPUT_MODE); //CS
 
  ioPinOTypeConfig(GPIOB, 15, Push_Pull);
  ioPinOTypeConfig(GPIOB, 14, Push_Pull);
  ioPinOTypeConfig(GPIOB, 13, Push_Pull);
 
  ioPinPullConfig(GPIOB, 15, PULL_UP);
  ioPinPullConfig(GPIOB, 14, PULL_UP);
  ioPinPullConfig(GPIOB, 13, PULL_UP);
 
  ioPinAlternateFunConfig(GPIOB, 15, AF5);
  ioPinAlternateFunConfig(GPIOB, 14, AF5);
  ioPinAlternateFunConfig(GPIOB, 13, AF5);
 
  ioPinSpeedConfig(GPIOB, 15, LOW_SPEED);
  ioPinSpeedConfig(GPIOB, 14, LOW_SPEED);
  ioPinSpeedConfig(GPIOB, 13, LOW_SPEED);
  ioPinSpeedConfig(GPIOB, 10, LOW_SPEED);
  ioPinSetReset(GPIOB, 10, SET_PIN);
  RCC->APB1ENR |= RCC_APB1ENR_SPI2EN;
  SPI2->CR1 = 0x00;
  SPI2->CR1 |= SPI_CR1_SSM | SPI_CR1_SSI | 0x05 << 3 | SPI_CR1_MSTR | SPI_CR1_CPOL | SPI_CR1_CPHA;
  SPI2->CR2 = 0x00;
  SPI2->CR1 |= SPI_CR1_SPE;
 
 
  writeRegister(SPI2, PWR_MGMNT_1, PWR_RESET);
  writeRegister(SPI2, 0x1B, 0x18);
 
  char buffer[16];
 
  while (1)
  {
 
    uint8_t whoAmIData = readRegister(SPI2, WHO_AM_I);
    sprintf(buffer, "WhoAmI: %d\r\n", whoAmIData);
    HAL_UART_Transmit(&huart2, buffer, strlen(buffer), HAL_MAX_DELAY);
 
  }
 
}
 
 
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
 
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
 
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 16;
  RCC_OscInitStruct.PLL.PLLN = 336;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
 
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}
 
static void MX_USART2_UART_Init(void)
{
 
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
 
}
 
static void MX_GPIO_Init(void)
{
 
  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
 
}
 
 
void Error_Handler(void)
{
 
}
 
void assert_failed(uint8_t *file, uint32_t line)
{ 
 
}

TDK
Guru

RXNE gets set every time a byte comes in. For SPI, this happens every time you send a byte. For single byte transfers, you should:

  1. wait for TXE
  2. Set SPIx->DR = x
  3. Wait for RXNE
  4. Read SPIx->DR to clear RXNE

You're not doing this on every byte transfer.

If you feel a post has answered your question, please click "Accept as Solution".
TRudn.1
Associate II

Yes again another mistake.... I assumed the SPIx->DR Register would be overridden.

The new Code works without a problem. Thank you guys very much. Since I'm very new to this low level type of programming without any HAL oder Arduino libraries this code still might not be efficient enough or any bad practice styles. If so I would be happy if you let me know :)

uint8_t readRegister(SPI_TypeDef *spih, uint8_t subAddress)
{
  uint8_t data;
  ioPinSetReset(GPIOB, 10, RESET_PIN);
  while(!(spih->SR & (SPI_SR_TXE)));
  spih->DR = (subAddress | SPI_READ);
  while(!(spih->SR & (SPI_SR_RXNE)));
  data = spih->DR;
 
  while(!(spih->SR & (SPI_SR_TXE)));
  spih->DR = 0x00;
  while(!(spih->SR & (SPI_SR_RXNE)));
  data = spih->DR;
  ioPinSetReset(GPIOB, 10, SET_PIN);
  return data;
}
 
void writeRegister(SPI_TypeDef *spih, uint8_t subAddress, uint8_t value)
{
  uint8_t tmp;
  ioPinSetReset(GPIOB, 10, RESET_PIN);
 
  while(!(spih->SR & (SPI_SR_TXE)));
  spih->DR = subAddress;
  while(!(spih->SR & (SPI_SR_RXNE)));
  tmp = spih->DR;
 
  while(!(spih->SR & (SPI_SR_TXE)));
  spih->DR = value;
  while(!(spih->SR & (SPI_SR_RXNE)));
  tmp = spih->DR;
 
  ioPinSetReset(GPIOB, 10, SET_PIN);
}

Grant Bt
Senior

Dumb newbie question. what is the (original) origin of "ioPinConfig( )". I know I have seen this before. It's not part of one of the ST or ARM headers is it?