STM8作为SPI从机无法回传数据

STM8 as SPI slave can't send back data

我已经用 STM8L 构建了一个原型板,我希望将其用作 SPI 从设备并配置为 SPI 从设备。我正在用 raspberry pi 作为主人测试它。

为此,我使用了 ST 提供的名为“STM8 标准外设库”的库,但是文档很差,并且没有说明如何执行此操作...

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

有人知道我怎样才能将一些数据发回给 Raspberry Pi master 吗?我的错误在哪里?

这里是主要代码:

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

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

我终于找到了我的错误所在。

首先,我忘记在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,软件工具不适合我的OS,所以我使用了一些工具来开发它。 我认为它对某些人有用,所以我在这里添加它:

首先,lib 不能用 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:

我明白回答硬件相关的问题并不容易。有没有人知道一些网站对这类问题比较详细?