Hello, Sorry for the offtopic. I am trying to connect LIS302DL motion sensor to the STM32F103 on our custom board over SPI bus. I was advised that Primer communicates to the motion sensors via SPI bus as well.
I didn't use additional schematics and directly connected CS, SCL, SDx, SDO of LIS302DL to the NSS, SCK, MOSI, MISO respectively (similarly as it is done in Primer).
With oscilloscope I can see perfectly shaped square signal on SCL and SDx. But SDO pin (that has to be sensor's output signal) produces saw-like signal where each period looks like triangle.
I have looked at Circle OS sources, that are available here: http://www.stm32circle.com/projects/project.php?id=49 and found that very interesting process is used there that is called 'SPI resynchronization' In general it tries to reinitialize SPI pins until it is possible to read Identification from motion sensor chip. (excerpt from MEMS_Init() is attached below)
So I wonder if there is anybody who could shed some light upon the concept behind SPI resynchronization or on possible reason of incorrect form of the SDO signal in my case.
A smallest comment will be hugely appreciated. Andrew.
Code:
/* Enable SPI */
SPI_Cmd( SPIX_MEMS, ENABLE );
if( MEMS_ReadID() != 0x3A )
{
int i;
// Try to resynchronize
for( i = 0 ; i < 17 ; i++ )
{
/* Configure SPI2 pins: SCK, MISO and MOSI */
GPIO_InitStructure.GPIO_Pin = GPIO_PIN_MEMS_SCK | GPIO_PIN_MEMS_MOSI;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init( GPIOX_MEMS_CTRL, &GPIO_InitStructure );
GPIO_WriteBit( GPIOX_MEMS_CTRL, GPIO_PIN_MEMS_MOSI, HIGH );
MEMS_ChipSelect( LOW );
GPIO_WriteBit( GPIOX_MEMS_CTRL, GPIO_PIN_MEMS_SCK, LOW );
GPIO_WriteBit( GPIOX_MEMS_CTRL, GPIO_PIN_MEMS_SCK, HIGH );
MEMS_ChipSelect( HIGH );
/* Configure again PB. SCK as SPI2 pin */
GPIO_InitStructure.GPIO_Pin = GPIO_PIN_MEMS_SCK | GPIO_PIN_MEMS_MOSI;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init( GPIOX_MEMS_CTRL, &GPIO_InitStructure );
if ( MEMS_ReadID() == 0x3A )
{
break;
}
}
if( i == 17 )
{
DRAW_DisplayString( 1, 50, "Test MEM ID Failed", 18 );
}
We introduced this resynchronization because there is no 'RESET' pin on this device. When you debug, you often stop a session randomly, and you always have the risk to interrupt a SPI communication within a byte transmission. A transmission is made of a certain number of clock (I don't remember but let say N). If after reading the IdCode, we don't find it, we assume that we are desymchronized and we send one clock more with the hope that the desymchronization was just one clock. If it does not work, we try again. With N tries, we are sure that must have encountered a synchronized situation. It works.
We introduced this resynchronization because there is no 'RESET' pin on this device. When you debug, you often stop a session randomly, and you always have the risk to interrupt a SPI communication within a byte transmission. A transmission is made of a certain number of clock (I don't remember but let say N). If after reading the IdCode, we don't find it, we assume that we are desymchronized and we send one clock more with the hope that the desymchronization was just one clock. If it does not work, we try again. With N tries, we are sure that must have encountered a synchronized situation. It works.
Hello Francis, Thanks for the information. This makes sense. But unfortunately it doesn't solve my problem with the triangular signal as I hoped. Will investigate furhter.
Hello Francis, yes, I set lowest possible bit-rate: SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
I am attaching my code below. In the main function I am trying to read identification register of the sensors. The code is relatively big, sorry for this. If you could tell me what I am doing wrong, I was in much debt to you.
Great thanks in advance
Code:
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x_lib.h"
/* Local includes ------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
typedef enum {FAILED = 0, PASSED = !FAILED} TestStatus;
/* Private define ------------------------------------------------------------*/
#define BufferSize 32
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
SPI_InitTypeDef SPI_InitStructure;
/* Private functions ---------------------------------------------------------*/
void RCC_Configuration(void);
void GPIO_Configuration(void);
void NVIC_Configuration(void);
void RCC_Configuration(void)
{
/* RCC system reset(for debug purpose) */
RCC_DeInit();
/* Enable HSE */
RCC_HSEConfig(RCC_HSE_ON);
/* Wait till HSE is ready */
ErrorStatus HSEStartUpStatus = RCC_WaitForHSEStartUp();
if (HSEStartUpStatus == SUCCESS)
{
/* HCLK = SYSCLK */
RCC_HCLKConfig(RCC_SYSCLK_Div1);
/* PCLK2 = HCLK/2 */
RCC_PCLK2Config(RCC_HCLK_Div2);
/* PCLK1 = HCLK/2 */
RCC_PCLK1Config(RCC_HCLK_Div2);
/* Enable Prefetch Buffer */
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
/* Flash 2 wait state */
FLASH_SetLatency(FLASH_Latency_2);
/* PLLCLK = 8MHz * 9 = 72 MHz */
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
/* Enable PLL */
RCC_PLLCmd(ENABLE);
/* Wait till PLL is ready */
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
{}
/* Select PLL as system clock source */
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
/* Wait till PLL is used as system clock source */
while (RCC_GetSYSCLKSource() != 0x08)
{}
}
/* Enable peripheral clocks --------------------------------------------------*/
/* GPIOA, GPIOB and SPI1 clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC |
RCC_APB2Periph_SPI1, ENABLE);
/* SPI2 Periph clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
}
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Configure SPI1 pins: SCK, MOSI ---------------------------------*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7; //GPIO_Pin_6 |
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;//GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//GPIO_Mode_Out_PP;//GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure SPI1 pins: MISO ---------------------------------*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; //GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//GPIO_Mode_Out_PP;//GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure SPI1 pins: SS ---------------------------------*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; //GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void NVIC_Configuration(void)
{
#ifdef VECT_TAB_RAM
/* Set the Vector Table base location at 0x20000000 */
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else /* VECT_TAB_FLASH */
/* Set the Vector Table base location at 0x08000000 */
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif
}
/*******************************************************************************
* Function Name : main
* Description : Main program
* Input : None
* Output : None
* Return : None
*******************************************************************************/
int main(void)
{
/* System clocks configuration ---------------------------------------------*/
RCC_Configuration();
/* NVIC configuration ------------------------------------------------------*/
NVIC_Configuration();
/* GPIO configuration ------------------------------------------------------*/
GPIO_Configuration();
/* 1st phase: SPI1 Master and SPI2 Slave */
/* SPI1 Config -------------------------------------------------------------*/
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; // SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//SPI_NSS_Soft; //SPI_NSS_Hard;//
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;//SPI_BaudRatePrescaler_4;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//SPI_FirstBit_LSB;
SPI_InitStructure.SPI_CRCPolynomial = 0;
SPI_Init(SPI1, &SPI_InitStructure);
/* Enable SPI1 */
SPI_Cmd(SPI1, ENABLE);
u16 request = 0x0F;//0x0F;//0x29; // OutX register
request |= 0x80; // RW bit =1 for reading
// request |= 0x40; // MS bit = 1 for address increment
// request <<= 8;
int i = 0;
int j = 0;
u16 buf[100]={0};
GPIO_ResetBits(GPIOA, GPIO_Pin_4);
// SPI_I2S_SendData(SPI1, request);
// SPI_I2S_SendData(SPI1, 0);
while(1)
{
//set low
GPIO_ResetBits(GPIOA, GPIO_Pin_4);
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI1, request);
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI1, 0);
//set high
GPIO_SetBits(GPIOA, GPIO_Pin_4);
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
{
buf[i++] = SPI_I2S_ReceiveData(SPI1);
i%=100;
}
j++;
}
while (1)
{}
}
Hello Francis, Thanks for the comment. I have changed clock polarity and clock phase. I also experimented with CPU frequency by changing mulitpliers in: RCC_PLLConfig(RCC_PLLSource_HSE_Div2, RCC_PLLMul_2); CPU frequency doesn't have any effect.
But changing the SPI baud prescaler SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; affects the shape of the output impulse from MEMS sensor. But it can't help make SDO pulses square.
I also have experimented with vdd_IO. This line is intended to power the inpu/output lines. I am not sure if this line is needed at all because sensor is working over I2C without this line connected.
It seems that from software point of view I have tried all variants.
It looks like a hardware issue... Did you try on two different boards? I guess you checked the CS pin (to switch between I2C and SPI). If you have a Primer (either Primer1 or Primer2), you can test your software running on the primer, then you could port it to your target board.
Fantastic !!! I have solved the problem by soldering 22K (I didn't have 10K) resistor between CS line and the ground, instead of setting Chip Select signal in software. It might look simple but for me it is real break-through. Dear sjoerd, Francis thank you so much for your help! It was really important to feel that you are not alone with your problems.. Thanks guys!