SPI_I2S_ReceiveData always returns 0xff or 0x00

2019-04-16 06:40发布

I want to create firmware to stm32f4 discovery wich 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;
}

标签: c embedded stm32
3条回答
我想做一个坏孩纸
2楼-- · 2019-04-16 07:31

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.

查看更多
神经病院院长
3楼-- · 2019-04-16 07:33

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;
}
查看更多
唯我独甜
4楼-- · 2019-04-16 07:33

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

  1. Select device.

  2. Write register address.

  3. Read register value.

  4. Deselect device.

查看更多
登录 后发表回答