树莓派4B运行SPI提速(MIT 机械狗程序)

MIT 主体代码不能直接运行,需要修改。其中:SPI通讯部分,默认代码运行会出现片选信号引脚无法拉低,导致树莓派与SPINE 通讯,只能在运行时发送一次数据,后续无法进入中断,

可以加上如下代码,调用树莓派自带库执行GPIO 操作,拉低在拉高

第一步:初始化ce0, ce1 引脚输出

int spi_open() {

  int rv = 0;
  // wiringPiSetup();
  // pinMode(ce0,OUTPUT);
  // pinMode(ce1,OUTPUT);
 bcm2835_init();
 bcm2835_gpio_fsel(ce0,BCM2835_GPIO_FSEL_OUTP);
 bcm2835_gpio_fsel(ce1,BCM2835_GPIO_FSEL_OUTP);
 



  spi_1_fd = open("/dev/spidev0.0", 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");

  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)");

  rv = ioctl(spi_1_fd, SPI_IOC_WR_MAX_SPEED_HZ, &spi_speed_wr);
  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_wr);
  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_rd);
  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_rd);
  if (rv < 0) perror("[ERROR] ioctl spi_ioc_rd_max_speed_hz (2)");

  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)");
  perror("[ERROR] here 2");
  return rv;
}

再将 

  spi_board == 0 ? bcm2835_gpio_write(ce0,LOW) : bcm2835_gpio_write(ce1,LOW);

  spi_board == 0 ? bcm2835_gpio_write(ce0,HIGH) : bcm2835_gpio_write(ce1,HIGH);

加入代码中。这样树莓派就可以正常发送SPI 数据了。

具体代码如下:

void spi_send_receive(spi_command_t *command, spi_data_t *data) {
  // update driver status flag
  spi_driver_iterations++;
  data->spi_driver_status = spi_driver_iterations << 16;

  // transmit and receive buffers
  uint16_t tx_buf[K_WORDS_PER_MESSAGE];
  uint16_t rx_buf[K_WORDS_PER_MESSAGE];


  for (int spi_board = 0; spi_board < 2; spi_board++) {
    // copy command into spine type:
    spi_to_spine(command, &g_spine_cmd, spi_board * 2);

    // pointers to command/data spine array
    uint16_t *cmd_d = (uint16_t *)&g_spine_cmd;
    uint16_t *data_d = (uint16_t *)&g_spine_data;

    // zero rx buffer
    memset(rx_buf, 0, K_WORDS_PER_MESSAGE * sizeof(uint16_t));

    // copy into tx buffer flipping bytes
    for (int i = 0; i < K_WORDS_PER_MESSAGE; i++)
 //    
      {
         tx_buf[i] = (cmd_d[i] >> 8) + ((cmd_d[i] & 0xff) << 8);
      }
    // tx_buf[i] = __bswap_16(cmd_d[i]);

    // each word is two bytes long
    size_t word_len = 1;  // 16 bit word         注意,为了提升SPI 传输速度, // 
    //spi_bits_per_word 由8-》16 

    // spi message struct
    struct spi_ioc_transfer spi_message[1];

    // zero message struct.
    memset(spi_message, 0, 1 * sizeof(struct spi_ioc_transfer));

    // set up message struct
    for (int i = 0; i < 1; i++) {
      spi_message[i].bits_per_word = spi_bits_per_word;  
      spi_message[i].cs_change = 1;
      spi_message[i].delay_usecs = 0;
      spi_message[i].word_delay_usecs =0;
      spi_message[i].len = word_len * K_WORDS_PER_MESSAGE;
      spi_message[i].rx_buf = (uint64_t)rx_buf;
      spi_message[i].tx_buf = (uint64_t)tx_buf;
    }

    // do spi communication
    // spi_board == 0 ? digitalWrite(ce0,0) : digitalWrite(ce1,0);
    spi_board == 0 ? bcm2835_gpio_write(ce0,LOW) : bcm2835_gpio_write(ce1,LOW); //加上这句,先拉低


   int rv = ioctl(spi_board == 0 ? spi_1_fd : spi_2_fd, SPI_IOC_MESSAGE(1),
                  &spi_message);

     spi_board == 0 ? bcm2835_gpio_write(ce0,HIGH) : bcm2835_gpio_write(ce1,HIGH); //再拉高
     

   (void)rv;

    // flip bytes the other way
    for (int i = 0; i < 30; i++)
      data_d[i] = (rx_buf[i] >> 8) + ((rx_buf[i] & 0xff) << 8);
    // data_d[i] = __bswap_16(rx_buf[i]);
    usleep(1);
    // copy back to data
 spine_to_spi(data, &g_spine_data, spi_board * 2);
  }
}

为了提升SPI 通讯速度,可以将报文帧缩短成两个报文

struct spi_command_t_goal
{
    float q_des_yaw[2];
    float q_des_pitch[2];
    float q_des_spin[2];
    float qd_des_yaw[2];
    float qd_des_pitch[2];
    float qd_des_spin[2]; 
    float tau_yaw_ff[2];
    float tau_pitch_ff[2];
    float tau_spin_ff[2];
    int32_t checksum;
};

struct spi_command_t_parameter
{
    float kp_yaw[2];
    float kp_pitch[2];
    float kp_spin[2];
    float kd_yaw[2];
    float kd_pitch[2];
    float kd_spin[2];
    int32_t flags[2];
    int8_t  motormode[6];
    int32_t checksum;
};

阻抗参数不是每次都配置,可以分开,每次发送运行位置信息,报文变短,发送速率会加快

unsigned char spi_bits_per_word = 8;


unsigned int spi_speed_wr = 4000000;   //可以将写的频率改为4M, 6M会乱码
unsigned int spi_speed_rd = 12000000;

    // each word is two bytes long
    size_t word_len = 2;  // 16 bit word

实测修改之前,树莓派运行MIT cheetah software 主体程序500HZ, 修改完可以达到1600HZ,不修改带宽上不去。而且乱码校验失败

运行结果截图:实测1000HZ+

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值