STM32 SPI从机模式无法正常传输

问题描述 投票:0回答:2

我使用STM32G030C8T6作为SPI(从设备),它从Raspberry pi(主设备)接收字符,接收工作完美!那里没有问题,但是当我尝试从 STM32 向 Pi 发送数据时,STM32 似乎卡住了一段时间,并且 Pi rx 缓冲区仅重复填充一位,例如,如果我发送 char buf[6] = { 0,1,2,3,4,5}; Pi 接收 (111111) 或 (333333),具体取决于我发送的字符数。

我到底想做什么?

我想将ADC数据从STM32(从模式)传输到Pi(主模式),到目前为止它只接收一位我重复。

有人可以帮我实现这个目标吗?

这是我的 SPI 配置:

void MX_SPI1_Init(void)
{

  /* USER CODE BEGIN SPI1_Init 0 */

  /* USER CODE END SPI1_Init 0 */

  /* USER CODE BEGIN SPI1_Init 1 */

  /* USER CODE END SPI1_Init 1 */
  /* SPI1 parameter configuration*/
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_SLAVE;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 7;
  hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
  hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI1_Init 2 */

  /* USER CODE END SPI1_Init 2 */

}

然后是读取字符、发送数据和字符串的函数

char SPI_read(void)
{
    // SPI1->SR is the STATUS REGISTER on SPI1 Bus
    // SPI1->DR is the DATA REGISTER on SPI1 Bus

    char data;
    while(!(SPI1->SR & SPI_SR_RXNE));


    while(SPI1->SR & SPI_SR_BSY);

    data = SPI1->DR;

    printmsg("%c",data);

    return data;
}


void spi_Send(char caracSend)
{
    while(!(SPI1->SR & SPI_SR_TXE));

    SPI1->DR = caracSend;
}


void spi_send_string(char* stringSend)
{
    int i=0;
    unsigned int sizeChar = 0;

    sizeChar = strlen(stringSend);

    __NOP();

    for(i=0;i<sizeChar;i++)
    {
        spi_Send(stringSend[i]);
    }
}

这是我从 Pi 接收数据的函数,我在主 while 循环中调用它。

void SPI_Receive_Commands(void)
{

    while(HAL_GPIO_ReadPin(SPI_SS_GPIO_Port, SPI_SS_Pin) == GPIO_PIN_RESET);
  {
        HAL_SPI_Receive(&hspi1, (uint8_t *)spi_buf, 10, 100);

    if(spi_buf[0] == 'v')
    {
      memset(spi_buf,'*',10);

      printmsg("Character V received\r\n");

      Battery_Voltage();
      spi_send_string(batteryVoltage);
      spi_Send('v');

      printmsg("Sending battery voltage\r\n");
    }
}
}

非常感谢您提前帮助我。

stm32 spi master-slave stm32f4discovery stm32cubeide
2个回答
1
投票
  1. 初始化。当您读取和写入字节时,您需要将 RX FIFO 阈值设置为 1/4。我不知道如何在 HAL 中做到这一点。寄存器级别只需设置

    FRXTH
    寄存器中的
    CR2

  2. DR
    寄存器必须以8位操作访问。

  3. 您不需要在轮询模式下使用 BSY 位,除非您想禁用 SPI 外设。

void spi_Send(char caracSend)
{
    while(!(SPI1->SR & SPI_SR_TXE));

    *(volatile uint8_t *)&SPI1->DR = caracSend;
}

void spi_send_string(char* str)
{
     if(str) while(*str) spi_Send(*str++);
}


char SPI_read(void)
{
    char data;
    while(!(SPI1->SR & SPI_SR_RXNE));

    data = *(volatile uint8_t *)&SPI1->DR;
    return data;
}

请记住,树莓派必须发送虚拟数据以允许从设备发送信息。从机生成时钟信号,并且时钟必须由主机

提供

0
投票

您可以使用STM32作为SPI从机,但SPI绝对不适用于发送/接收字符串。它用于从从设备读取和写入精确的寄存器。 SPI 外设(如果我没记错的话)只有 16 位缓冲区。

如果必须发送 ascii 解码字符串,则应该选择较慢的异步协议。

如果您必须使用 SPI 更快地读取数据,则应从从机发送值而不进行 ASCII 解码。

我建议使用 STM32CubeIDE 及其从 .ioc 文件生成代码。它将对 SPI 进行低级初始化。你所需要使用的就是这两个函数:

HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)

SPI Echo 示例(1 字节命令,1 字节数据/我手动设置从机选择引脚/如果需要单独读取和写入数据,并且需要实现设定值回读,可以使用 FromMaster/ToMaster 数组改进此代码):

void SPI_Slave_Process(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, SPI_HandleTypeDef *hspi, uint8_t* FromMaster, uint8_t* ToMaster) {
    static uint8_t RxData;
    static uint8_t TxData;
    while(!(HAL_GPIO_ReadPin(GPIOx, GPIO_Pin))) {
        HAL_SPI_Receive(hspi, &RxData, 1, 2);
        TxData = RxData;
        HAL_SPI_Transmit(hspi, &TxData, 1, 2);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.