1

我已经用 STM8L 构建了一个原型板,我希望它可以用作和配置为 SPI 从机。我正在用树莓派作为主人对其进行测试。

为此,我使用 ST 提供的名为“STM8 Standard Peripherals Library”的库,但文档很差,并没有说明如何做到这一点......

我可以毫无问题地从 Raspberry Pi 发送数据并在 STM8 上接收它,但我无法从 MISO 上的 STM8 将任何数据发送回覆盆子。

有人知道我如何将一些数据发送回 Raspberry Pi 主机吗?我的错误在哪里?

这是主要代码:

void main(void)
{
  // GPIO
  GPIO_Init(GPIOA, GPIO_Pin_7, GPIO_Mode_Out_PP_Low_Fast);
  CLK_Config();
  

  // Set the MOSI and SCK at high level 
  GPIO_ExternalPullUpConfig(GPIOB, GPIO_Pin_6 | GPIO_Pin_5, ENABLE);
  
  SPI_DeInit(SPI1);

  SPI_Init(SPI1, SPI_FirstBit_LSB, SPI_BaudRatePrescaler_2, SPI_Mode_Slave,
           SPI_CPOL_Low, SPI_CPHA_2Edge, SPI_Direction_2Lines_FullDuplex,
           SPI_NSS_Hard, (uint8_t)0x07);

  SPI_BiDirectionalLineConfig(SPI1, SPI_Direction_Tx);


  // Enable SPI
  SPI_Cmd(SPI1, ENABLE);


  /* Infinite loop */
  while (1)
  {
    while(SPI_GetFlagStatus(SPI1, SPI_FLAG_BSY));

    // SPI polling
    if(SPI_GetFlagStatus(SPI1, SPI_FLAG_RXNE) == SET) {

      while(SPI_GetFlagStatus(SPI1, SPI_FLAG_BSY));
      
      GPIO_ToggleBits(GPIOA, GPIO_Pin_7);
      
      uint8_t data = SPI_ReceiveData(SPI1);

      while(SPI_GetFlagStatus(SPI1, SPI_FLAG_BSY));

      // I can't send back data here, it doesn't work
      SPI_SendData(SPI1, 0xFA);

      uint8_t test = SPI1->DR;

      GPIO_ResetBits(GPIOA, GPIO_Pin_7);
    }
  }
}


static void CLK_Config(void)
{
  /* Select HSE as system clock source */
  CLK_SYSCLKSourceSwitchCmd(ENABLE);
  CLK_SYSCLKSourceConfig(CLK_SYSCLKSource_HSI);
  
  /*High speed external clock prescaler: 1*/
  CLK_SYSCLKDivConfig(CLK_SYSCLKDiv_2);

  while (CLK_GetSYSCLKSource() != CLK_SYSCLKSource_HSI)
  {}

  /* Enable SPI clock */
  CLK_PeripheralClockConfig(CLK_Peripheral_SPI1, ENABLE);
}

RPi 简单代码:

#include <iostream>
#include <wiringPi.h>
#include <wiringPiSPI.h>

using namespace std;

int main()
{
    wiringPiSetup();
    wiringPiSPISetup(0, 50000);

    unsigned char data[] = {0x5A};

    wiringPiSPIDataRW(0, data, 2);

    std::cout<<data<<std::endl;


    return 0;

谢谢您的帮助!:)

编辑:我认为错误出在 uC 代码中,因为 spi 数据寄存器在我读取后仍然包含主机发送的数据。即使尝试直接在寄存器中写入,我也无法更改它。

另外:设备只包含一个SPI数据寄存器是否正常?如果没有一个用于 MOSI (Rx) 和一个用于 MISO(Tx),它应该如何是全双工的?我想我对 SPI 有一些不明白的地方。我对这个串行协议不是很有经验。我之前主要使用I2C。

4

2 回答 2

1

SPI 需要主机提供时钟。如果你想让从机发送一些东西——你的主机 必须发送一些虚拟数据来为从机生成时钟。

于 2021-09-26T17:05:01.850 回答
1

我终于发现我的错误在哪里。

首先,我忘了在 MISO 引脚上配置一个上拉电阻:

  // Set the MOSI and SCK at high level 
  GPIO_ExternalPullUpConfig(GPIOB, GPIO_Pin_6 | GPIO_Pin_5 | GPIO_Pin_7, ENABLE);

接下来,SPI 配置错误。Rpi 位于 MSB 中,STM8 位于 LSB 中,当需要位于第一个边沿时,相位位于第二个边沿:

  SPI_Init(SPI1, SPI_FirstBit_MSB, SPI_BaudRatePrescaler_2, SPI_Mode_Slave,
           SPI_CPOL_Low, SPI_CPHA_1Edge, SPI_Direction_2Lines_FullDuplex,
           SPI_NSS_Hard, (uint8_t)0x07);

最后,这不是一个错误,而是一种不是最佳的测试方法:我与主服务器发送 0x81,但它是二进制对称的(0b10000001)。我应该发送一些不对称的消息,例如 0x17 (0b00010111)。

以及完整的STM8代码:

#include "stm8l15x.h"
#include "stm8l15x_it.h"    /* SDCC patch: required by SDCC for interrupts */

static void CLK_Config(void);
void Delay(__IO uint16_t nCount);

void main(void)
{
  // GPIO
  GPIO_Init(GPIOA, GPIO_Pin_7, GPIO_Mode_Out_PP_Low_Fast);
  CLK_Config();
  

  // Set the MOSI and SCK at high level (I added MOSI)
  GPIO_ExternalPullUpConfig(GPIOB, GPIO_Pin_6 | GPIO_Pin_5 | GPIO_Pin_7, ENABLE);
  
  SPI_DeInit(SPI1);

  SPI_Init(SPI1, SPI_FirstBit_MSB, SPI_BaudRatePrescaler_2, SPI_Mode_Slave,
           SPI_CPOL_Low, SPI_CPHA_1Edge, SPI_Direction_2Lines_FullDuplex,
           SPI_NSS_Hard, (uint8_t)0x07);

  SPI_BiDirectionalLineConfig(SPI1, SPI_Direction_Tx);


  // Enable SPI
  SPI_Cmd(SPI1, ENABLE);


  /* Infinite loop */
  while (1)
  {
    while(SPI_GetFlagStatus(SPI1, SPI_FLAG_BSY));

    // SPI polling
    if(SPI_GetFlagStatus(SPI1, SPI_FLAG_RXNE) == SET) {

      // maybe this line is not necessary, I didn't have the time to test without it yet 
      while(SPI_GetFlagStatus(SPI1, SPI_FLAG_BSY);
      
      uint8_t data = SPI_ReceiveData(SPI1);

      while(SPI_GetFlagStatus(SPI1, SPI_FLAG_RXNE));
      
      if(data==0x82) SPI_SendData(SPI1, 0xCD);

      GPIO_ResetBits(GPIOA, GPIO_Pin_7);
    }
  }
}

/* Private functions ---------------------------------------------------------*/

static void CLK_Config(void)
{
  /* Select HSE as system clock source */
  CLK_SYSCLKSourceSwitchCmd(ENABLE);
  CLK_SYSCLKSourceConfig(CLK_SYSCLKSource_HSI);
  
  /*High speed external clock prescaler: 1*/
  CLK_SYSCLKDivConfig(CLK_SYSCLKDiv_2);

  while (CLK_GetSYSCLKSource() != CLK_SYSCLKSource_HSI)
  {}

  /* Enable SPI clock */
  CLK_PeripheralClockConfig(CLK_Peripheral_SPI1, ENABLE);
}

void Delay(__IO uint16_t nCount)
{
  /* Decrement nCount value */
  while (nCount != 0)
  {
    nCount--;
  }
}

/*******************************************************************************/



#ifdef  USE_FULL_ASSERT

void assert_failed(uint8_t* file, uint32_t line)
{ 
  /* Infinite loop */
  while (1)
  {
  }
}
#endif

PS:

我在 linux 上,软件工具不适合我的操作系统,所以我使用了一些工具来开发它。我认为它可能对某些人有用,所以我在这里添加它:

首先,该库无法使用 SDCC 进行编译,所以我使用了我在这里找到的补丁: https ://github.com/gicking/STM8-SPL_SDCC_patch

要上传到 uC,我使用带有 ST-LINK V2 的 stm8flash: https ://github.com/vdudouyt/stm8flash

我也很难找到 STM8L 的库。这是: https ://www.st.com/en/embedded-software/stsw-stm8016.html

PS2:

我知道回答硬件相关问题并不容易。有谁知道一些在这类问题上更具体的网站?

于 2021-09-27T15:38:09.627 回答