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+