【问题标题】:Reading values of SPI data register of STM32 MCUSTM32单片机SPI数据寄存器读取值
【发布时间】:2019-01-10 06:50:06
【问题描述】:

有很多类似的问题,但似乎没有一个问题完全相同。我将 STML4 MCU 连接到 6 轴传感器 (LSM6DS3)。我已经成功地实现了 I2C 中的所有内容,但想要 SPI(和 DMA,如果我能让这些第一步工作......)的额外速度。所以第一步,我试图读取设备的WHO_AM_I 寄存器(0x0F),它应该回复0x69。代码如下:

uint8_t who = 0;

// Sanity check/debugging aid should get 0x5D
who = 0x43 + 0x1A;

// Set SS low
GPIO_WritePin (GPIOB, LL_GPIO_PIN_7, GPIO_PIN_RESET);

// while tx buffer is in use, wait
while (!LL_SPI_IsActiveFlag_TXE(SPI1));

// Send READ command to the WHO_AM_I register
(SPI1->DR) = 0x8F;

// while rx buffer is in use, wait
while (!LL_SPI_IsActiveFlag_RXNE(SPI1));

// Get data off the register
who = (SPI1->DR);

// Wait for everything to wrap up before setting SS high again
while (LL_SPI_IsActiveFlag_BSY(SPI1));

// OK, now we can set SS high
GPIO_WritePin (GPIOB, LL_GPIO_PIN_7, GPIO_PIN_SET);

在示波器/分析仪上,我看到一切都按预期运行,包括传感器发回0x69。但是,当我在此代码块的另一侧设置中断时,我看到 who0 变为 0x5D 再到 0xFF。它从不读取0x69。我查看了其他代码示例,有些人进行了第二次传输,数据设置为某个虚拟值(通常为0xFF0x0),所以我也尝试过,但传感器似乎在第二次尝试时感到困惑,并且who 最终成为 0x48。我已经尝试了等待我可以拥有的RXNE/TXE/BSY 标志的所有排列,以及许多其他让变量正确读取SPI1 数据寄存器的方法,包括读取其他注册了传感器,但都无济于事。

那么问题来了,如何正确读取这个寄存器的值?

我还应该提到我可以成功写入设备的寄存器。我可以发送我想要的命令,然后将其读回并查看它是否适用于范围,即使我永远无法在代码中获得分配给变量的值。我总是收到0xFF

我的分析仪屏幕显示传感器从单个读取请求发回0x69,以及如果我尝试“虚拟传输”方法它发送的乱码。

【问题讨论】:

    标签: c embedded hardware stm32 spi


    【解决方案1】:

    SPI 始终(如果启用接收器)在您传输时接收数据。

    这是库的问题,您不知道那里有什么。 SPI 使用寄存器更容易编程。

    我假设你的数据是 8 位的。

    您需要在 SPI 初始化期间通过以下方式设置 1/4(一个字节)FIFO 阈值:

     SPI1 -> CR2 |= SPI_CR2_FRXTH;
    

    接下来您需要在每次写入后从 FIFO 中读取数据(您还需要强制编译器使用正确的大小(在本例中为 8 位)加载和存储指令):

    *(volatile uint8_t *)&SPI1->DR = 0x8F;  // write exactly 8 bits to the FIFO
    while (!LL_SPI_IsActiveFlag_RXNE(SPI1));
    dummy = *(volatile uint8_t *)&SPI-> DR;
    *(volatile uint8_t *)&SPI1->DR = 0;  // dummy write
    while (!LL_SPI_IsActiveFlag_RXNE(SPI1));
    who = *(volatile uint8_t *)&(SPI1->DR);
    

    我不知道使用 LL 库有什么意义。

    而不是

    while (!LL_SPI_IsActiveFlag_RXNE(SPI1));
    

    使用寄存器

    while (!(SPI1 -> SR & SPI_SR_RNE));
    

    您也可以将其包装到函数中:

    uint8_t SPI_ReadWrite8(SPI_TypeDef *spi, uint8_t data)
    {
        while(!(spi -> SR & SPI_SR_TXE));
        *(volatile uint8_t *)&spi->DR = data; 
        while (!(spi -> SR & SPI_SR_RNE));
        return *(volatile uint8_t *)&spi-> DR;
    }
    

    还有

    SPI_ReadWrite8(SPI1, 0x8f);
    who = SPI_ReadWrite8(SPI1, 0);
    

    【讨论】:

    • 谢谢!除了设置季度 FIFO 阈值外,我实际上已经完成了您在此处提到的所有操作。我在上面以 LL 形式给出它的唯一原因是为了清楚起见。我也尝试过它自己的功能,我只是认为将它全部放在同一个代码块中会更容易。但是,我试了一下,就像你在这里一样(修复函数中的类型 - 它应该是 RXNE),我得到几乎相同的响应,尽管现在 who 在结尾。不过示波器信号看起来是一样的。
    • 你设置阈值了吗?
    • 你使用 *(volatile uint8_t *) 访问吗?
    • 是的,是的。但是,我刚刚开始工作。出于某种原因,用SPI_SR_BSY 替换SPI_SR_RXNE 给了我正确的值。我不认为您可能对这会有什么不同有所了解?
    • 您设置了 DS 吗? (SPI1 -> CR2 &= ~(SPI_CR2_DS_Msk); SPI1 -> CR2 |= 0b111 << SPI_CR2_DS_Pos;)
    猜你喜欢
    • 2020-07-15
    • 1970-01-01
    • 2020-03-01
    • 2018-11-10
    • 2021-06-17
    • 2022-01-02
    • 2020-06-11
    • 1970-01-01
    • 2021-12-30
    相关资源
    最近更新 更多