今天又进行了SPI的相关测试,化简了测试代码,分别写了上位机的测试代码与下位机的接收代码,当前可以收到SPI的数据,但是CS片选没有起作用,两个STM32同时向总线发送数据,导致数据错误。如果仅使用一个STM32,则两个SPI接收的数据相同。

其中STM32的代码略去了不相干的部分,具体代码可以查看我的仓库1仓库2

#include <cmath>
#include <iostream>
#include <unistd.h>

#include <byteswap.h>
#include <math.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <string>

#include <linux/spi/spidev.h>

unsigned char spi_mode          = SPI_MODE_0; // 时钟极性0,时钟相位0
unsigned char spi_bits_per_word = 8;          // 每个字8字节
unsigned int  spi_speed         = 6000000;    // 6M
uint8_t       lsb               = 0x01;

int spi_1_fd = -1;
int spi_2_fd = -1;

/*!
 * Compute SPI message checksum
 * @param data : input
 * @param len : length (in 32-bit words)
 * @return
 */
uint32_t xor_checksum(uint32_t* data, size_t len)
{
    uint32_t t = 0;
    for (size_t i = 0; i < len; i++)
        t = t ^ data[i];
    return t;
}

/*!
 * Open SPI device
 * 启动spi设备
 */
int spi_open()
{
    // 打开spi
    printf("[RT SPI] Open\n");
    int rv = 0; // receive value
    // 通过打开文件的方式打开设备吗? fd=file device
    spi_1_fd = open("/dev/spidev0.0", O_RDWR); // O_RDWR :文件可读可写
    if (spi_1_fd < 0)
        perror("[ERROR] Couldn't open spidev 2.0");
    spi_2_fd = open("/dev/spidev0.1", O_RDWR);
    if (spi_2_fd < 0)
        perror("[ERROR] Couldn't open spidev 2.1");
    // ioctl:Input output control.设置一些io信息
    // spi_mode 设置极性与相位
    rv = ioctl(spi_1_fd, SPI_IOC_WR_MODE, &spi_mode);
    if (rv < 0)
        perror("[ERROR] ioctl spi_ioc_wr_mode (1)");
    rv = ioctl(spi_2_fd, SPI_IOC_WR_MODE, &spi_mode);
    if (rv < 0)
        perror("[ERROR] ioctl spi_ioc_wr_mode (2)");

    rv = ioctl(spi_1_fd, SPI_IOC_RD_MODE, &spi_mode);
    if (rv < 0)
        perror("[ERROR] ioctl spi_ioc_rd_mode (1)");
    rv = ioctl(spi_2_fd, SPI_IOC_RD_MODE, &spi_mode);
    if (rv < 0)
        perror("[ERROR] ioctl spi_ioc_rd_mode (2)");
    // 设置每个字有几个字节
    rv = ioctl(spi_1_fd, SPI_IOC_WR_BITS_PER_WORD, &spi_bits_per_word);
    if (rv < 0)
        perror("[ERROR] ioctl spi_ioc_wr_bits_per_word (1)");
    rv = ioctl(spi_2_fd, SPI_IOC_WR_BITS_PER_WORD, &spi_bits_per_word);
    if (rv < 0)
        perror("[ERROR] ioctl spi_ioc_wr_bits_per_word (2)");

    rv = ioctl(spi_1_fd, SPI_IOC_RD_BITS_PER_WORD, &spi_bits_per_word);
    if (rv < 0)
        perror("[ERROR] ioctl spi_ioc_rd_bits_per_word (1)");
    rv = ioctl(spi_2_fd, SPI_IOC_RD_BITS_PER_WORD, &spi_bits_per_word);
    if (rv < 0)
        perror("[ERROR] ioctl spi_ioc_rd_bits_per_word (2)");
    // 设置spi通信速度 6M
    rv = ioctl(spi_1_fd, SPI_IOC_WR_MAX_SPEED_HZ, &spi_speed);
    if (rv < 0)
        perror("[ERROR] ioctl spi_ioc_wr_max_speed_hz (1)");
    rv = ioctl(spi_2_fd, SPI_IOC_WR_MAX_SPEED_HZ, &spi_speed);
    if (rv < 0)
        perror("[ERROR] ioctl spi_ioc_wr_max_speed_hz (2)");

    rv = ioctl(spi_1_fd, SPI_IOC_RD_MAX_SPEED_HZ, &spi_speed);
    if (rv < 0)
        perror("[ERROR] ioctl spi_ioc_rd_max_speed_hz (1)");
    rv = ioctl(spi_2_fd, SPI_IOC_RD_MAX_SPEED_HZ, &spi_speed);
    if (rv < 0)
        perror("[ERROR] ioctl spi_ioc_rd_max_speed_hz (2)");
    // 采用lsb模式
    rv = ioctl(spi_1_fd, SPI_IOC_RD_LSB_FIRST, &lsb);
    if (rv < 0)
        perror("[ERROR] ioctl spi_ioc_rd_lsb_first (1)");
    rv = ioctl(spi_2_fd, SPI_IOC_RD_LSB_FIRST, &lsb);
    if (rv < 0)
        perror("[ERROR] ioctl spi_ioc_rd_lsb_first (2)");

    return rv;
}

void spi_close()
{
    close(spi_1_fd);
    close(spi_2_fd);
}

std::string hex2str(const uint8_t* str, int len)
{
    static const char hexTable[17] = "0123456789ABCDEF";

    std::string result;
    for (int i = 0; i < len; ++i)
    {
        result += "0x";
        result += hexTable[(unsigned char)str[i] / 16];
        result += hexTable[(unsigned char)str[i] % 16];
        result += " ";
    }
    return result;
}

int transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len)
{
    struct spi_ioc_transfer tr = {
        .tx_buf = (uint64_t)tx,
        .rx_buf = (uint64_t)rx,
        .len = len,
        .speed_hz = spi_speed,
        .delay_usecs = 0,
        .bits_per_word = spi_bits_per_word,
        .cs_change = 1,
    };

    int ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
    if (ret < 1)
        printf("can't send spi message\n");

    return ret;
}

int main()
{
    spi_open();

    uint8_t tx[16];
    uint8_t rx_1[16];
    uint8_t rx_2[16];

    for (int i = 0; i < 16; ++i)
    {
        tx[i] = i;
    }

    int rv = transfer(spi_1_fd, tx, rx_1, 16);
    (void)rv;
    auto str = hex2str(rx_1, 16);
    std::cout << "[SPI1]" << str << std::endl;

    rv = transfer(spi_2_fd, tx, rx_2, 16);
    (void)rv;
    str = hex2str(rx_2, 16);
    std::cout << "[SPI2]" << str << std::endl;

    spi_close();

    return 0;
}
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
int state = 1;
static uint8_t tx[16];
static uint8_t rx[16];
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_CAN1_Init();
  MX_CAN2_Init();
  MX_SPI1_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */
  for(int i = 0; i < 16; ++i)
  {
    tx[i] = 16 - i;
  }

  HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, state);
  HAL_SPI_TransmitReceive_IT(&hspi1, tx, rx, 16);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    //HAL_SPI_TransmitReceive(&hspi1, tx, rx, 16, 10);
    //HAL_UART_Transmit(&huart2, "hello", 6, 100);
    HAL_Delay(1000);
  }
  /* USER CODE END 3 */
}

/* USER CODE BEGIN 4 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  if(GPIO_Pin == SPI_CS_Pin)
  {
    if(HAL_GPIO_ReadPin(SPI_CS_GPIO_Port, SPI_CS_Pin) == GPIO_PIN_RESET)
    {
      state = !state;
      HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, state);
      HAL_SPI_TransmitReceive_IT(&hspi1, tx, rx, 16);
    }
  }
}

void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
  // TX Done .. Do Something ...
}
/* USER CODE END 4 */