【问题标题】:SPI Communication between STM32 and ADXL345STM32和ADXL345之间的SPI通信
【发布时间】:2021-12-11 06:12:05
【问题描述】:

我正在尝试使用 SPI 通信从 ADXL345 加速度计读取数据。我在主模式下配置了不同的引脚和 SPI,并尝试读取 x、y 和 z 轴加速度。

我的问题是 SPI 读数始终为 0。我尝试调试以找到问题,我意识到即使我正在传输数据并且我不明白为什么,RXNE 也从未设置。

我正在使用 STM32F103 开发板。

这是我的代码:

#include "Driver_GPIO.h"

#include "stm32f10x.h"

uint8_t RxData[6];
int x,y,z;
float   x_acc,y_acc,z_acc;

void GPIO_Config (void)
{

    
    MyGPIO_Struct_TypeDef NSS={GPIOA,4,Out_OD}; // Output Open Drain
    MyGPIO_Struct_TypeDef SCK={GPIOA,5,AltOut_Ppull}; // Alternate Output Push-Pull
    MyGPIO_Struct_TypeDef MISO={GPIOA,6,In_Floating}; // Input Floating
    MyGPIO_Struct_TypeDef MOSI={GPIOA,7,AltOut_Ppull}; // Alternate Output Push-Pull

    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; //enable GPIOA clk
    
    MyGPIO_Init(&NSS);
    MyGPIO_Init(&SCK);
    MyGPIO_Init(&MISO);
    MyGPIO_Init(&MOSI);
}
    

void SPI_Enable (void)
{
    SPI1->CR1 |= (SPI_CR1_SPE);   // SPE=1, Peripheral enabled
}

void SPI_Disable (void)
{
    SPI1->CR1 &= ~(SPI_CR1_SPE);   // SPE=0, Peripheral Disabled
}

void CS_Enable (void)
{
    GPIOA->BSRR |= GPIO_BSRR_BR9;
}

void CS_Disable (void)
{
    GPIOA->BSRR |= GPIO_BSRR_BS9;
}

void SPI_Config(void){
  RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;  // Enable SPI1 CLock
    
  SPI1->CR1 |= SPI_CR1_CPOL| SPI_CR1_CPHA;   // CPOL=1, CPHA=1
    
  SPI1->CR1 |= SPI_CR1_MSTR;  // Master Mode
    
  SPI1->CR1 |= (SPI_CR1_BR_0)| (SPI_CR1_BR_1);  // BR[2:0] = 400: fPCLK/16, PCLK2 = 72MHz, SPI clk = 3.375MHz
    
  SPI1->CR1 &= ~SPI_CR1_LSBFIRST;  // LSBFIRST = 0, MSB first
    
  SPI1->CR1 |= (SPI_CR1_SSM) | (SPI_CR1_SSI);  // SSM=1, SSI=1 -> Software Slave Management
    
  SPI1->CR1 &= ~SPI_CR1_RXONLY;  // RXONLY = 0, full-duplex
    
  SPI1->CR1 &= ~SPI_CR1_DFF;  // DFF=0, 8 bit data
    
  SPI1->CR2 = 0;

}

void SPI_Transmission(uint8_t *data, int size){
    uint8_t clear;
    //check flag TxE //
    int i=0;
    while (i<size)
    {
        while (!((SPI1->SR)&(SPI_SR_TXE))){};  // buffer is empty
        *(volatile uint8_t *)&SPI1->DR = data[i];
        i++;
    }
    
    while (!((SPI1->SR)&(SPI_SR_TXE))){};  // buffer is empty

    while (((SPI1->SR)&(SPI_SR_BSY))){}; // buffer not communicating

    
    clear= SPI1->DR; // empty Overrun flag
    clear= SPI1->SR;
}

void SPI_Receive (uint8_t *data,int size)
{
    while (size)
    {
        while (((SPI1->SR)&(SPI_SR_BSY))) {};  // buffer not communicating
        *(volatile uint8_t *)&SPI1->DR = 0;  // dummy data
        while (!((SPI1->SR) &(SPI_SR_RXNE))){};
        // buffer is not empty
        *data++= *(volatile uint8_t *)&SPI1->DR;
        size--;
    }
}

void adxl345_write (uint8_t address, uint8_t value)
{
    uint8_t data[2];
    data[0] = address|0x40;  // multibyte write
    data[1] = value;
    CS_Enable ();  // pull the cs pin low
    SPI_Transmission (data,2);  // write data to register
    CS_Disable ();  // pull the cs pin high
}
    

void adxl345_read (uint8_t address, uint8_t *RxData)
{
    address |= 0x80;  // read operation
    address |= 0x40;  // multibyte read
    CS_Enable ();  // pull the pin low
    SPI_Transmission (&address,1);  // send address
    SPI_Receive (RxData,6);  // receive 6 bytes data
    CS_Disable ();;  // pull the pin high
}

void adxl345_init (void)
{
    adxl345_write (0x31, 0x01);  // data_format range= +- 4g
    adxl345_write (0x2d, 0x00);  // reset all bits
    adxl345_write (0x2d, 0x08);  // power_cntl measure and wake up 8hz
}
int main(void)
    
{ 
    GPIO_Config();
    SPI_Config();
    SPI_Enable();
    adxl345_init();

    do{
        adxl345_read(0x32,RxData);
        x = ((RxData[1]<<8)|RxData[0]); // DATA X0, X1
        y = ((RxData[3]<<8)|RxData[2]); // DATA Y0, Y1
        z = ((RxData[5]<<8)|RxData[4]); // DATA Z0, Z1
        
        // Scale Factor for Xout, Yout and Zout is 7.8 mg/LSB for a +-4g, 10-bit resolution
        // ==> multiply by 0.0078 to get real acceleration values
        
        x_acc= x * 0.0078; 
        y_acc= y * 0.0078;
        z_acc= z * 0.0078;
        
    }while(1);
    

}

【问题讨论】:

  • 请对所有代码使用相同的格式规则,不要混合不同的编码风格。 Driver_GPIO.h 里面是什么?当您在传输数据时测量任何使用过的 SPI 线路时,​​您是否使用示波器看到了什么?
  • Driver_GPIO.h 仅用于配置我的 4 个引脚(SCK、MOSI、MISO、NSS)。我也没有示波器所以没试过。
  • 您不应该检查 TXE=1 标志是否已准备好传输,而不仅仅是 BUSY 标志吗?顺便说一句。您实际上可以先尝试读取 DEVID,以检查您的 SPI 通信吗?然后检查芯片的设置。
  • @kesselhaus 这很有道理,我会补充一点。同样通过 DEVID,您的意思是读取 0x00 地址吗? (我是一个初学者,所以我很抱歉)。如果是,我确实尝试过,但什么也读不出来(又是 0..)。
  • *(volatile uint8_t *)&amp;SPI1-&gt;DR 非常可疑。为什么选演员?隐藏错误不会让它们消失。

标签: c embedded stm32 spi stm32f1


【解决方案1】:

如前所述,这里有很多问题

  1. 为什么 NSS 引脚配置为漏极开路?通常 CS 线是推挽式的。我不知道原理图,但这是我第一次看到开漏 CS
  2. GPIO_Config NSS 中是针脚 4,但针脚 9 是从 CS_Enable 切换的
  3. 如果 F1 系列有单独的时钟位用于备用功能,则未启用

您说 RXNE 始终为零并且读数返回零也很奇怪。如果 RXNE 保持为零,您的代码应该停留在 while 循环中

【讨论】:

  • 我完全同意,可能是第一项,因为我在 ADXL345 原理图上看到了上拉电阻。
  • @mryldz OD 带上拉电阻会导致缓慢的上升沿。如果交换很少见也没关系。但是,如果交换频繁且没有停顿 - CS 可能不会在传输之间上升到逻辑一级,这反过来可能会中断后续传输。你需要一台示波器才能确定
  • @Flexz 由于 NSS 是在软件模式下配置的,RM 说“未使用。可以用作 GPIO”,所以我真的不知道该怎么做。每当我写入数据时,我仍然需要将 cs 引脚拉低/拉高。我的代码也卡在第一个 RXNE while 循环中,因为它始终为 0。
  • @zalix,那么哪个引脚连接到 ADXL345 的 nCS 输入?如果是PA9,那么它在哪里配置?它必须是推挽式gpio输出。默认情况下,所有引脚都是输入。如果 PA4 不用于 SPI 通信 - 确认无关紧要
【解决方案2】:

我不会分析幻数,因为我没有时间检查 RM 中的每个数字。但是你有很多明显的问题。

  1. 启用外设时钟后需要延迟或回读。您立即设置了错误的寄存器。添加__DSB(); 或回读(例如(void)RCC-&gt;APB2ENR;)。所有外围设备都相同

【讨论】:

  • 嗯 .. 在这样的评论之前最好阅读文档 .. The peripheral registers have to be accessed by half-words (16 bits) or words (32 bits). 所以,即使DR 寄存器也应该以 16 位而不是 8 位访问。
  • @kesselhaus 你说得对 - 我已经很多年没有使用 f1 了。较新的有先进先出,这种铸造是必要的
猜你喜欢
  • 2021-12-31
  • 2019-06-14
  • 2021-08-27
  • 2021-11-22
  • 2019-04-06
  • 1970-01-01
  • 2021-03-04
  • 2022-01-20
  • 2017-04-14
相关资源
最近更新 更多