【问题标题】:STM32F4 SPI issueSTM32F4 SPI问题
【发布时间】:2016-03-03 04:09:32
【问题描述】:

我正在使用STM32F407vg,我正在尝试向SPI数据寄存器中写入数据,以下代码显示了配置功能

void init_SPI1(void){

GPIO_InitTypeDef GPIO_InitStruct;
SPI_InitTypeDef SPI_InitStruct;

// enable clock for used IO pins
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

/* configure pins used by SPI1
     * PA4 = NSS
 * PA5 = SCK
 * PA6 = MISO
 * PA7 = MOSI
 */
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6 | GPIO_Pin_5|GPIO_Pin_4;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStruct);

// connect SPI1 pins to SPI alternate function
GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);

//Set chip select high 
GPIOA->BSRRL |= GPIO_Pin_4; // set PE4 high

// enable peripheral clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

/* configure SPI1 in Mode 0 
 * CPOL = 0 --> clock is low when idle
 * CPHA = 0 --> data is sampled at the first edge
 */
SPI_StructInit(&SPI_InitStruct); // set default config 
SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // set to full duplex mode, seperate MOSI and MISO lines
SPI_InitStruct.SPI_Mode = SPI_Mode_Master;     // transmit in master mode, NSS pin has to be always high
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; // one packet of data is 8 bits wide
SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;        // clock is low when idle
SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;      // data sampled at first edge
SPI_InitStruct.SPI_NSS = SPI_NSS_Soft ; // set the NSS management to internal and pull internal NSS high
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; // SPI frequency is APB2 frequency / 4
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;// data is transmitted MSB first
SPI_Init(SPI1, &SPI_InitStruct); 

SPI_Cmd(SPI1, ENABLE); // enable SPI1
} 

这是发送数据的函数

 uint8_t SPI1_send(uint8_t data){

SPI1->DR = data; // write data to be transmitted to the SPI data register
while( !(SPI1->SR & SPI_I2S_FLAG_TXE) ); // wait until transmit complete
while( !(SPI1->SR & SPI_I2S_FLAG_RXNE) ); // wait until receive complete
while( SPI1->SR & SPI_I2S_FLAG_BSY ); // wait until SPI is not busy anymore
return SPI1->DR; // return received data from SPI data register
}

我认为我已经设置了很好的配置(我认为引脚的选择没有错以及所使用的总线的配置)以下图片摘自STM32F407 DataSheet

问题是 DR 注册表中的数据与作为参数 传递的数据不同。我不知道为什么会发生这种情况。谁能指导我正确的点

【问题讨论】:

    标签: c embedded stm32 spi


    【解决方案1】:

    SPI DR 寄存器不是一个普通的内存位置,写入和读取访问相同的存储。

    相反,写入会加载输出移位寄存器,而读取会读取接收到的输入。根据设备详细信息,读取还可以“声明”输入,将其从寄存器中清除,直到接收到另一个字。

    由于这些原因,尝试使用调试器查看 SPI DR 不仅不会为您提供所需的信息,甚至可能会损坏您原本会收到的数据。

    【讨论】:

    • 感谢 Chris 的回复,但我真的不明白为什么我无法从调试器中读取 SPI DR 以及如何确保我的数据已成功写入
    • 您无法读取它,因为硬件不支持读取您写入的“侧面”。要恢复传输数据,您可以使用逻辑分析仪,或者您可以断开 SPI 外围设备(或拒绝激活其芯片选择)并将 SPI MOSI 引脚循环回 MISO,以便程序最终能够回读在正确的时间传输数据不要尝试使用调试器,因为它会在错误的时间读取。调试器不是魔法——它们有非常实际的局限性,除非你愿意了解并尊重它们,否则你无法很好地使用它。
    • 最终,无论如何尝试恢复您刚刚在发送寄存器中设置的数据几乎没有任何目的 - 如果您对代码有真正的疑问,请查看反汇编。如果您想证明您正在设置您认为的值,请查看其中一个配置寄存器。但请记住,一些特殊功能寄存器仅对给定的字宽有效 - 尝试以错误的宽度读取不一定会给您部分数据和/或额外的废话位,就像内存访问一样,它可能会完全失败,因为这些不是内存位置。
    • 再次感谢您的回复,我停用了芯片选择,然后我将 SPI MOSI 引脚循环回 MISO 引脚,在指令中返回 SPI1->DR 我应该有正确的值,但是它不是我得到分层值(0x08,0x26 ...)的情况,你认为我错过了什么问题是什么
    【解决方案2】:

    在阅读this book 的 SPI 部分后,我的问题解决了,我只需将 SPI MOSI 连接到 SPI MISO 引脚(PA6 和 PA7),然后使用以下功能:

    int spiReadWrite(SPI_TypeDef* SPIx, uint8_t *rbuf,
    const uint8_t *tbuf, int cnt, enum spiSpeed speed)
    {
    int i;
    SPIx->CR1 = (SPIx->CR1 & ~SPI_BaudRatePrescaler_256) |
    speeds[speed];
    for (i = 0; i < cnt; i++){
      if (tbuf) {
      SPI_I2S_SendData(SPIx, *tbuf++);
      } else {
      SPI_I2S_SendData(SPIx, 0xff);
      }
    while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == RESET);
      if (rbuf) {
      *rbuf++ = SPI_I2S_ReceiveData(SPIx);
      } else {
      SPI_I2S_ReceiveData(SPIx);
      }
    }
    return i;
    }
    

    通过使用调试器,我可以看到发送的数据(来自 tbuf)已成功接收(在 rbuf 中)

    【讨论】:

      【解决方案3】:

      注意 SCLK_freq = APB2_freq / (BaudRatePrescaler + 1)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-04-04
        • 2021-05-02
        • 2019-04-25
        • 2021-12-09
        • 2016-04-18
        • 2019-09-09
        • 2012-02-10
        • 1970-01-01
        相关资源
        最近更新 更多