cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 SPI Spoiled Bits

0901123w
Associate II
Posted on October 06, 2014 at 13:11

Hello,

I have a problem trying to communicate with SPI using the STM32 Nucleo. I am using the STM_HAL_Drivers to read data from an Invensense MPU9 When I read values, I sometimes get spoilage of the last bit, and this seems to coincide with the value of the MISO line when the register address is being sent (i.e if the MISO line is high when transmiting the register address, the recieved data will spoil high, and vice versa). I have checked all lines using an Oscilloscope and the data seems to be fine.


/* Includes ------------------------------------------------------------------*/

#include ''stm32f4xx_hal.h''


/* Private variables ---------------------------------------------------------*/

SPI_HandleTypeDef hspi1;


UART_HandleTypeDef huart2;


/* USER CODE BEGIN 0 */

#include ''MPU_SPI.h''

#define HAL_SPI_MODULE_ENABLED

#define MPU_Add 0x68<<1

#define MPU_WHO_AM_I 0x75


/* USER CODE END 0 */


/* Private function prototypes -----------------------------------------------*/

void
SystemClock_Config(
void
);

static
void
MX_GPIO_Init(
void
);

static
void
MX_SPI1_Init(
void
);

static
void
MX_USART2_UART_Init(
void
);


int
main(
void
)

{


/* USER CODE BEGIN 1 */


/* USER CODE END 1 */


/* MCU Configuration----------------------------------------------------------*/


/* Reset of all peripherals, Initializes the Flash interface and the Systick. */

HAL_Init();


/* Configure the system clock */

SystemClock_Config();


/* System interrupt init*/

/* Sets the priority grouping field */

HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_0);

HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);


/* Initialize all configured peripherals */

MX_GPIO_Init();

MX_SPI1_Init();

MX_USART2_UART_Init();


/* USER CODE BEGIN 2 */

uint8_t *Buffer = 
''Hello World -> 1\n''
;


uint8_t *Space = 
''\n''
;

uint8_t *address[4]; 
//245 or f5


char
data[100];

int
*pdata =data;


HAL_Delay(500);

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);

HAL_Delay(100);

func_SPI_Write_Byte(0x6B, 0x80, data); 
//__works

HAL_Delay(100);


func_SPI_Write_Byte(User_Control, 0x10, data); 
//__works

HAL_Delay(100);


func_SPI_Write_Byte(0x6B, 0x00, data); 
//__works

HAL_Delay(100);


func_SPI_Write_Byte(I2C_MST_Ctrl, 0x00, data);

func_SPI_Write_Byte(I2C_MST_Ctrl, 0x4D, data);

func_SPI_Write_Byte(User_Control, 0x60, data);


HAL_UART_Transmit(&huart2, Buffer, strlen(Buffer), 5000);

HAL_Delay(2000);


/* USER CODE END 2 */


/* USER CODE BEGIN 3 */

/* Infinite loop */


while
(1){

//this will read the contents of the MPU_Who_AM_I register

//passing results to the ''data''

func_SPI_Write_Byte((MPU_WHO_AM_I|0x80),0x00, data); 
//__works


//this will read the contents of the MPU_Who_AM_I register

//This transmits 2 characters of ''data'' to be viewed on cutecom

HAL_UART_Transmit(&huart2, data, 2, 0x1000);


//this will pass the contents of the MAG_Who_AM_I register into ext_sensor_4 register

//it will then read this register passing results to the ''data''

//since it is an external sensor it requires more configuration

func_SPI_Read_Ext_Sens_Byte(MAG_who_am_i,data);


HAL_UART_Transmit(&huart2, data, 2, 0x1000);


func_SPI_Read_Ext_Sens_Byte(MAG_who_am_i,data);


HAL_UART_Transmit(&huart2, data, 2, 0x1000);


func_SPI_Write_Byte((MPU_WHO_AM_I|0x80),0x00, data);

HAL_UART_Transmit(&huart2, data, 2, 0x1000);


func_SPI_Write_Byte((MPU_WHO_AM_I|0x80),0x00, data);

HAL_UART_Transmit(&huart2, data, 2, 0x1000);


HAL_Delay(2000);

}

/* USER CODE END 3 */


}


/** System Clock Configuration

*/

void
SystemClock_Config(
void
)

{


RCC_ClkInitTypeDef RCC_ClkInitStruct;

RCC_OscInitTypeDef RCC_OscInitStruct;


__PWR_CLK_ENABLE();


__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);


RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;

RCC_OscInitStruct.HSIState = RCC_HSI_ON;

RCC_OscInitStruct.HSICalibrationValue = 6;

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 = 7;

HAL_RCC_OscConfig(&RCC_OscInitStruct);


RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1;

RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;

RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;

RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;

RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);


}


/* SPI1 init function */

void
MX_SPI1_Init(
void
)

{


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_HIGH;

hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;

hspi1.Init.NSS = SPI_NSS_HARD_OUTPUT;

hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;

hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;

hspi1.Init.TIMode = SPI_TIMODE_DISABLED;

hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;

HAL_SPI_Init(&hspi1);


}


/* USART2 init function */
5

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;

HAL_UART_Init(&huart2);


}


/** Configure pins as 

* Analog 

* Input 

* Output

* EVENT_OUT

* EXTI

*/

void
MX_GPIO_Init(
void
)

{


GPIO_InitTypeDef GPIO_InitStruct;


/* GPIO Ports Clock Enable */

__GPIOC_CLK_ENABLE();

__GPIOH_CLK_ENABLE();

__GPIOA_CLK_ENABLE();

__GPIOB_CLK_ENABLE();


/*Configure GPIO pin : PC13 */

GPIO_InitStruct.Pin = GPIO_PIN_13;

GPIO_InitStruct.Mode = GPIO_MODE_EVT_RISING;

GPIO_InitStruct.Pull = GPIO_NOPULL;

HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);


/*Configure GPIO pin : PB6 */

GPIO_InitStruct.Pin = GPIO_PIN_6;

GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

GPIO_InitStruct.Pull = GPIO_NOPULL;

GPIO_InitStruct.Speed = GPIO_SPEED_LOW;

HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);


}


/* USER CODE BEGIN 4 */

/* int temp[6];

int i;

float value[2];

for (i=0;i<2;i++){

func_SPI_Write_Byte((MPU_Acc_X_H |0x80 + i),0x00, j);

HAL_UART_Transmit(&huart2, &data, strlen(&data), 0x1000);

HAL_UART_Transmit(&huart2, Space, strlen(Space), 0x1000);

temp[i]= data[2];


}

//for (i =0; i<3;i++){

int temp2[2];

temp2[0] = (int)(temp[i*2]<<8);

temp2[1] = (int)temp[i*2+1];


int16_t temp3 = (int16_t)(temp2[0] | temp2[1]);

value[i] = (float)((temp3)/16384);

//}


HAL_UART_Transmit(&huart2, &value, strlen(&value), 0x1000); //__works


*/

/* USER CODE END 4 */


#ifdef USE_FULL_ASSERT


/**

* @brief Reports the name of the source file and the source line number

* where the assert_param error has occurred.

* @param file: pointer to the source file name

* @param line: assert_param error line source number

* @retval None

*/

void
assert_failed(uint8_t* file, uint32_t line)

{

/* USER CODE BEGIN 6 */

/* User can add his own implementation to report the file name and line number,

ex: printf(''Wrong parameters value: file %s on line %d\r\n'', file, line) */

/* USER CODE END 6 */


}


#endif


/**

* @}

*/


/**

* @}

*/


/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

The MPU_SPI header file includes the following functions and the MPU register addresses.


void
func_SPI_Write_Byte(uint8_t address, uint8_t data, 
char
*j){

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);

uint8_t Write_data[2];

Write_data[0] = address;

Write_data[1] = data;

HAL_SPI_TransmitReceive(&hspi1, &Write_data, j, 2, 0x1000);

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);

return
;


}



void
func_SPI_Read_Ext_Sens_Byte(uint8_t address, 
char
*j){

func_SPI_Write_Byte(I2C_SLV4_ADD,(MAG_Add|0x80),j);

func_SPI_Write_Byte(I2C_SLV4_REG, address,j);

func_SPI_Write_Byte(I2C_SLV4_CTRL, 0x80,j);

func_SPI_Write_Byte((I2C_SLV4_DI|0x80), 0x00,j);

}

The MPU_Who_AM_I and the MAG_Who_Am_I are both set registers with values of 71 and 48 respectively. All this should produce .ExternalClassE97C7A5D5F78478BA9AA6DD4C930DF18 p, .ExternalClassE97C7A5D5F78478BA9AA6DD4C930DF18 li {white-space:pre-wrap;}

ff 71 ff 48 00 48 00 71 ff 71

however it produces

ff 71 ff 49 00 48 00 70 ff 71

Any help would be greatly recieved and apologies for the wall of code, I have little experience of both using this forum and of microprocessors... #spi-stm32-problem-mpu9250
12 REPLIES 12
0901123w
Associate II
Posted on October 08, 2014 at 08:56

I don't quite understand how this is possible - LSB corrupted, when the difference of the waveforms is close to MSB of the read byte...

Can you disconnect the sensor and experiment with MOSI looped back to MISO?

JW
0901123w
Associate II
Posted on October 08, 2014 at 13:31

OK I still don't understand, but what if you simply avoid the HAL stuff?

void

func_SPI_Write_Byte(uint8_t address, uint8_t data,

char

*j){

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);   while ((SPI1->SR & SPI_SR_TXE) == 0);  SPI1->DR = address;  while((SPI1->SR & SPI_SR_RXNE) == 0);  *j++ = SPI1->DR;  

while ((SPI1->SR & SPI_SR_TXE) == 0);  SPI1->DR = 0x00;  while((SPI1->SR & SPI_SR_RXNE) == 0);  *j++ = SPI1->DR; 

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);

return

;

Posted on October 08, 2014 at 13:52

Oh, and post the content of all SPI registers, taken during or after communication.

JW
0901123w
Associate II
Posted on October 08, 2014 at 14:24

I've managed to get it to work using SPI2 port, and I'll try your suggestions and report back. Thanks

Posted on October 08, 2014 at 14:44

> I've managed to get it to work using SPI2 port

Using the *same* software?

Hummmm...

JW
jgr
Associate
Posted on January 08, 2015 at 14:35

Hi,

I have seen this issue as well but on the Nucleo L152 board using SPI1. Did you find any solution to this bit error issue?

Thanks, Jonas.

baddogno
Associate
Posted on May 06, 2015 at 17:39

Hi, I am having the exact same problem with an STM32L151. Did you find a solution?

I tried SPI1 ansd SPI2 ports and it did not change a thing. The clock polarities are correct. I even isolated my SPI port by doing a MOSI/MISO loopback on my board and saw the LSB interpreted incorrectly by the micro versus the oscilloscope. I duplicated the test on an STM32F4Discovery board and it worked just fine. 

I have a temporary workaround for now as I just wrote a bit banged SPI transmit and receive function to take the SPI peripheral out of the service. That works fine so I can continue to develop but there is clearly a problem somewhere and I was wondering if anyone else has found a solution?

Thanks