Reputation: 3363
I want to create firmware to stm32f4 discovery which flashes the lights, when the board moves. But SPI_I2S_ReceiveData
always returns 0xff or 0x00. I think the problem is in my SPI initialization but I do not know where exactly it is.
Here is my code.
#include <stm32f4xx.h>
#include <stm32f4xx_rcc.h>
#include <stm32f4xx_gpio.h>
#include <stm32f4xx_spi.h>
#include <stm32f4xx_i2c.h>
void InitLEDs(void);
void InitSPI(void);
void Delay(int iTicks);
void DiodeFlash(void);
unsigned short ReadACCELEROMETER(void);
unsigned char WriteSPI(unsigned char cbData);
int main(void)
{
unsigned short cbPrevRead = 0;
unsigned short cbCurrentRead = 0;
InitLEDs();
InitSPI();
while(1)
{
cbCurrentRead = ReadACCELEROMETER();
if (cbCurrentRead != cbPrevRead)
{
DiodeFlash();
cbPrevRead = cbCurrentRead;
}
}
}
void InitLEDs(void)
{
GPIO_InitTypeDef PortD;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
PortD.GPIO_Mode = GPIO_Mode_OUT;
PortD.GPIO_OType = GPIO_OType_PP;
PortD.GPIO_PuPd = GPIO_PuPd_NOPULL;
PortD.GPIO_Speed = GPIO_Speed_100MHz;
PortD.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_Init(GPIOD, &PortD);
}
void InitSPI(void)
{
GPIO_InitTypeDef PortA;
GPIO_InitTypeDef PortE;
SPI_InitTypeDef SPI1Conf;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
PortA.GPIO_Mode = GPIO_Mode_AF;
PortA.GPIO_OType = GPIO_OType_PP;
PortA.GPIO_Speed = GPIO_Speed_50MHz;
PortA.GPIO_PuPd = GPIO_PuPd_NOPULL;
PortA.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_Init(GPIOA, &PortA);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);
PortE.GPIO_Mode = GPIO_Mode_OUT;
PortE.GPIO_OType = GPIO_OType_PP;
PortE.GPIO_Speed = GPIO_Speed_50MHz;
PortE.GPIO_PuPd = GPIO_PuPd_NOPULL;
PortE.GPIO_Pin = GPIO_Pin_3;
GPIO_Init(GPIOE, &PortE);
GPIOE->ODR = 0x0008; // Disable CS
SPI1Conf.SPI_DataSize = SPI_DataSize_8b;
SPI1Conf.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;
SPI1Conf.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI1Conf.SPI_FirstBit = SPI_FirstBit_MSB; // ACCELEROMETER PROTOCOL
SPI1Conf.SPI_Mode = SPI_Mode_Master;
SPI1Conf.SPI_CPHA = SPI_CPHA_2Edge;
SPI1Conf.SPI_CPOL = SPI_CPOL_High;
SPI1Conf.SPI_CRCPolynomial = 7;
SPI1Conf.SPI_NSS = SPI_NSS_Soft;
SPI_Init(SPI1, &SPI1Conf);
SPI_Cmd(SPI1, ENABLE);
WriteSPI(0x23); WriteSPI(0xc9);
WriteSPI(0x20); WriteSPI(0x97);
WriteSPI(0x24); WriteSPI(0x00);
WriteSPI(0x10); WriteSPI(0x00);
WriteSPI(0x11); WriteSPI(0x00);
WriteSPI(0x12); WriteSPI(0x00);
}
void Delay(int iTicks)
{
while ((iTicks--) > 0);
}
void DiodeFlash(void)
{
GPIO_Write(GPIOD, 1UL << 12);
Delay(100000);
GPIO_Write(GPIOD, 1UL << 13);
Delay(100000);
GPIO_Write(GPIOD, 1UL << 14);
Delay(100000);
GPIO_Write(GPIOD, 1UL << 15);
Delay(100000);
GPIO_Write(GPIOD, 0x0000);
}
unsigned short ReadACCELEROMETER(void)
{
unsigned short nAxisX = 0x0000;
unsigned short nAxisY = 0x0000;
unsigned short nAxisZ = 0x0000;
unsigned char cbAddress = 0x80;
//**********************************************************
// Forming X Value
WriteSPI(cbAddress | 0x0f);
nAxisX |= WriteSPI(0x00);
WriteSPI(cbAddress | 0x2A);
nAxisX |= WriteSPI(0x00) << 8;
//**********************************************************
// Forming Y Value
WriteSPI(cbAddress | 0x2B);
nAxisX |= WriteSPI(0x00);
WriteSPI(cbAddress | 0x2C);
nAxisX |= WriteSPI(0x00) << 8;
//**********************************************************
// Forming Z Value
WriteSPI(cbAddress | 0x2D);
nAxisX |= WriteSPI(0x00);
WriteSPI(cbAddress | 0x2E);
nAxisX |= WriteSPI(0x00) << 8;
return nAxisX ^ nAxisY ^ nAxisZ;
}
unsigned char WriteSPI(unsigned char cbData)
{
unsigned char cbResult = 0x00;
GPIOE->ODR = 0x0000; // Enable CS
// Wait for ready status
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET);
SPI_I2S_SendData(SPI1, cbData);
// Wait for ready status
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET);
cbResult = SPI_I2S_ReceiveData(SPI1);
GPIOE->ODR = 0x0008; // Disable CS
return cbResult;
}
Upvotes: 1
Views: 3227
Reputation:
There is nothing wrong with your SPI initialization. The main mistake is in writing register addresses. You must not deselect device before reading register values, instead you must perform write address - reading values in one batch. It mean
Select device.
Write register address.
Read register value.
Deselect device.
Upvotes: 1
Reputation:
It is beacuse you writes address of register, after deselects your device, so wrote address is clean up. In this case you must do something like this.
unsigned char WriteSPI(unsigned char cbData)
{
unsigned char cbResult = 0x00;
// Wait for ready status
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET);
SPI_I2S_SendData(SPI1, cbData);
// Wait for ready status
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET);
cbResult = SPI_I2S_ReceiveData(SPI1);
return cbResult;
}
unsigned char WriteReg(unsigned char cbAddress, unsigned char cbData)
{
unsigned char cbResult = 0x00;
GPIOE->ODR = 0x0000; // select device
WriteSPI(cbAddress);
cbResult = WriteSPI(cbData);
GPIOE->ODR = 0x0008; // deselect device
return cbResult;
}
unsigned char ReadReg(unsigned char cbAddress)
{
unsigned char cbResult = 0x00;
GPIOE->ODR = 0x0000; // select device
WriteSPI(cbAddress);
cbResult = WriteSPI(0x00);
GPIOE->ODR = 0x0008; // deselect device
return cbResult;
}
Upvotes: 1
Reputation: 549
First, you don't specify your accelerometer. I can guess, that it is ST LISxx.
In this case, there is incorrect data transfer to accelerometer.
Correct write sequence:
- activate chipselect
- write register number
- write register value
- deactivate chipselect
Use similar sequence to read each register.
Next, ST not recommend your algo for low-level SPI transfer:
Do not use the BSY flag to handle each data transmission or reception. It is better to use the TXE and RXNE flags instead
(see Reference manual). Use simply
SPIx->DR = out;
while (!(SPIx->SR & SPI_SR_RXNE)) ;
return SPIx->DR;
Also, i am working with LIS3DH with CPOL=0 & CPHA = 0 SPI settings (i don't know, how it will work with your CPOL=1, CPHA=1).
Hint: to check SPI communication, try to read WHO_AM_I register - it is alawys enabled and always have known value.
Upvotes: 3