From 9dd00575632651dfaf049e9676f1134c3e4bb406 Mon Sep 17 00:00:00 2001 From: chenfu <2412777093@qq.com> Date: Sat, 23 Dec 2023 11:09:36 +0800 Subject: [PATCH] Correct spi chip selection --- Src/spi.c | 4 +- application/cmd/robot_cmd.c | 86 ++++++++++++++++++------------------- application/gimbal/gimbal.c | 24 +---------- application/robot.c | 12 +++--- application/robot_task.h | 44 +++++++++---------- bsp/spi/bsp_spi.c | 40 ++++++++++++++++- bsp/spi/bsp_spi.h | 3 +- modules/BMI088/bmi088.c | 22 +++++----- 8 files changed, 125 insertions(+), 110 deletions(-) diff --git a/Src/spi.c b/Src/spi.c index ea60ff8..70000fe 100644 --- a/Src/spi.c +++ b/Src/spi.c @@ -137,7 +137,7 @@ void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle) hdma_spi1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_spi1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_spi1_rx.Init.Mode = DMA_NORMAL; - hdma_spi1_rx.Init.Priority = DMA_PRIORITY_HIGH; + hdma_spi1_rx.Init.Priority = DMA_PRIORITY_VERY_HIGH; hdma_spi1_rx.Init.FIFOMode = DMA_FIFOMODE_ENABLE; hdma_spi1_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; hdma_spi1_rx.Init.MemBurst = DMA_MBURST_SINGLE; @@ -158,7 +158,7 @@ void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle) hdma_spi1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_spi1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_spi1_tx.Init.Mode = DMA_NORMAL; - hdma_spi1_tx.Init.Priority = DMA_PRIORITY_HIGH; + hdma_spi1_tx.Init.Priority = DMA_PRIORITY_VERY_HIGH; hdma_spi1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; if (HAL_DMA_Init(&hdma_spi1_tx) != HAL_OK) { diff --git a/application/cmd/robot_cmd.c b/application/cmd/robot_cmd.c index 49bd404..4b91006 100644 --- a/application/cmd/robot_cmd.c +++ b/application/cmd/robot_cmd.c @@ -50,48 +50,48 @@ BMI088Instance *bmi088_test; // 云台IMU BMI088_Data_t bmi088_data; void RobotCMDInit() { - BMI088_Init_Config_s bmi088_config = { - .cali_mode = BMI088_CALIBRATE_ONLINE_MODE, - .work_mode = BMI088_BLOCK_TRIGGER_MODE, - .spi_acc_config = { - .spi_handle = &hspi1, - .GPIOx = GPIOA, - .cs_pin = GPIO_PIN_4, - .spi_work_mode = SPI_DMA_MODE, - }, - .acc_int_config = { - .GPIOx = GPIOC, - .GPIO_Pin = GPIO_PIN_4, - .exti_mode = GPIO_EXTI_MODE_RISING, - }, - .spi_gyro_config = { - .spi_handle = &hspi1, - .GPIOx = GPIOB, - .cs_pin = GPIO_PIN_0, - .spi_work_mode = SPI_DMA_MODE, - }, - .gyro_int_config = { - .GPIO_Pin = GPIO_PIN_5, - .GPIOx = GPIOC, - .exti_mode = GPIO_EXTI_MODE_RISING, - }, - .heat_pwm_config = { - .htim = &htim10, - .channel = TIM_CHANNEL_1, - .period = 1, - }, - .heat_pid_config = { - .Kp = 0.5, - .Ki = 0, - .Kd = 0, - .DeadBand = 0.1, - .Improve = PID_Trapezoid_Intergral | PID_Integral_Limit | PID_Derivative_On_Measurement, - .IntegralLimit = 100, - .MaxOut = 100, - }, - }; - bmi088_test = BMI088Register(&bmi088_config); - rc_data = RemoteControlInit(&huart3); // 修改为对应串口,注意如果是自研板dbus协议串口需选用添加了反相器的那个 + // BMI088_Init_Config_s bmi088_config = { + // .cali_mode = BMI088_CALIBRATE_ONLINE_MODE, + // .work_mode = BMI088_BLOCK_TRIGGER_MODE, + // .spi_acc_config = { + // .spi_handle = &hspi1, + // .GPIOx = GPIOA, + // .cs_pin = GPIO_PIN_4, + // .spi_work_mode = SPI_DMA_MODE, + // }, + // .acc_int_config = { + // .GPIOx = GPIOC, + // .GPIO_Pin = GPIO_PIN_4, + // .exti_mode = GPIO_EXTI_MODE_RISING, + // }, + // .spi_gyro_config = { + // .spi_handle = &hspi1, + // .GPIOx = GPIOB, + // .cs_pin = GPIO_PIN_0, + // .spi_work_mode = SPI_DMA_MODE, + // }, + // .gyro_int_config = { + // .GPIO_Pin = GPIO_PIN_5, + // .GPIOx = GPIOC, + // .exti_mode = GPIO_EXTI_MODE_RISING, + // }, + // .heat_pwm_config = { + // .htim = &htim10, + // .channel = TIM_CHANNEL_1, + // .period = 1, + // }, + // .heat_pid_config = { + // .Kp = 0.5, + // .Ki = 0, + // .Kd = 0, + // .DeadBand = 0.1, + // .Improve = PID_Trapezoid_Intergral | PID_Integral_Limit | PID_Derivative_On_Measurement, + // .IntegralLimit = 100, + // .MaxOut = 100, + // }, + // }; + //bmi088_test = BMI088Register(&bmi088_config); + rc_data = RemoteControlInit(&huart3); // 修改为对应串口,注意如果是自研板dbus协议串口需选用添加了反相器的那个 vision_recv_data = VisionInit(&huart1); // 视觉通信串口 gimbal_cmd_pub = PubRegister("gimbal_cmd", sizeof(Gimbal_Ctrl_Cmd_s)); @@ -319,7 +319,7 @@ static void EmergencyHandler() /* 机器人核心控制任务,200Hz频率运行(必须高于视觉发送频率) */ void RobotCMDTask() { - BMI088Acquire(bmi088_test,&bmi088_data) ; + // BMI088Acquire(bmi088_test,&bmi088_data) ; // 从其他应用获取回传数据 #ifdef ONE_BOARD SubGetMessage(chassis_feed_sub, (void *)&chassis_fetch_data); diff --git a/application/gimbal/gimbal.c b/application/gimbal/gimbal.c index b42178e..b8a99a9 100644 --- a/application/gimbal/gimbal.c +++ b/application/gimbal/gimbal.c @@ -17,29 +17,7 @@ static Gimbal_Ctrl_Cmd_s gimbal_cmd_recv; // 来自cmd的控制信息 static BMI088Instance *bmi088; // 云台IMU void GimbalInit() { - //gimba_IMU_data = INS_Init(); // IMU先初始化,获取姿态数据指针赋给yaw电机的其他数据来源 - BMI088_Init_Config_s imu_config = { - .work_mode = BMI088_BLOCK_PERIODIC_MODE, - .spi_acc_config = { - .spi_handle = &hspi1, - .GPIOx = GPIOA, - .cs_pin = GPIO_PIN_4, - .spi_work_mode = SPI_BLOCK_MODE, - }, - .spi_gyro_config = { - .spi_handle = &hspi1, - .GPIOx = GPIOA, - .cs_pin = GPIO_PIN_4, - .spi_work_mode = SPI_BLOCK_MODE, - }, - .heat_pwm_config = { - .htim = &htim10, - .channel = TIM_CHANNEL_1, - .period = 1, - } - - }; - bmi088=BMI088Register(&imu_config); + gimba_IMU_data = INS_Init(); // IMU先初始化,获取姿态数据指针赋给yaw电机的其他数据来源 // YAW Motor_Init_Config_s yaw_config = { .can_init_config = { diff --git a/application/robot.c b/application/robot.c index 7124ab4..3102179 100644 --- a/application/robot.c +++ b/application/robot.c @@ -31,12 +31,12 @@ void RobotInit() #if defined(ONE_BOARD) || defined(GIMBAL_BOARD) RobotCMDInit(); - //GimbalInit(); - //ShootInit(); + GimbalInit(); + ShootInit(); #endif #if defined(ONE_BOARD) || defined(CHASSIS_BOARD) - //ChassisInit(); + ChassisInit(); #endif OSTaskInit(); // 创建基础任务 @@ -49,12 +49,12 @@ void RobotTask() { #if defined(ONE_BOARD) || defined(GIMBAL_BOARD) RobotCMDTask(); - //GimbalTask(); - //ShootTask(); + GimbalTask(); + ShootTask(); #endif #if defined(ONE_BOARD) || defined(CHASSIS_BOARD) - //ChassisTask(); + ChassisTask(); #endif } \ No newline at end of file diff --git a/application/robot_task.h b/application/robot_task.h index 557ac90..561f316 100644 --- a/application/robot_task.h +++ b/application/robot_task.h @@ -17,13 +17,13 @@ #include "bsp_log.h" -// osThreadId insTaskHandle; +osThreadId insTaskHandle; osThreadId robotTaskHandle; osThreadId motorTaskHandle; osThreadId daemonTaskHandle; osThreadId uiTaskHandle; -// void StartINSTASK(void const *argument); +void StartINSTASK(void const *argument); void StartMOTORTASK(void const *argument); void StartDAEMONTASK(void const *argument); void StartROBOTTASK(void const *argument); @@ -35,8 +35,8 @@ void StartUITASK(void const *argument); */ void OSTaskInit() { - // osThreadDef(instask, StartINSTASK, osPriorityAboveNormal, 0, 1024); - // insTaskHandle = osThreadCreate(osThread(instask), NULL); // 由于是阻塞读取传感器,为姿态解算设置较高优先级,确保以1khz的频率执行 + osThreadDef(instask, StartINSTASK, osPriorityAboveNormal, 0, 1024); + insTaskHandle = osThreadCreate(osThread(instask), NULL); // 由于是阻塞读取传感器,为姿态解算设置较高优先级,确保以1khz的频率执行 // // 后续修改为读取传感器数据准备好的中断处理, osThreadDef(motortask, StartMOTORTASK, osPriorityNormal, 0, 256); @@ -54,24 +54,24 @@ void OSTaskInit() HTMotorControlInit(); // 没有注册HT电机则不会执行 } -// __attribute__((noreturn)) void StartINSTASK(void const *argument) -// { -// static float ins_start; -// static float ins_dt; -// INS_Init(); // 确保BMI088被正确初始化. -// LOGINFO("[freeRTOS] INS Task Start"); -// for (;;) -// { -// // 1kHz -// ins_start = DWT_GetTimeline_ms(); -// //INS_Task(); -// ins_dt = DWT_GetTimeline_ms() - ins_start; -// if (ins_dt > 1) -// LOGERROR("[freeRTOS] INS Task is being DELAY! dt = [%f]", &ins_dt); -// VisionSend(); // 解算完成后发送视觉数据,但是当前的实现不太优雅,后续若添加硬件触发需要重新考虑结构的组织 -// osDelay(1); -// } -// } +__attribute__((noreturn)) void StartINSTASK(void const *argument) +{ + static float ins_start; + static float ins_dt; + INS_Init(); // 确保BMI088被正确初始化. + LOGINFO("[freeRTOS] INS Task Start"); + for (;;) + { + // 1kHz + ins_start = DWT_GetTimeline_ms(); + INS_Task(); + ins_dt = DWT_GetTimeline_ms() - ins_start; + if (ins_dt > 1) + LOGERROR("[freeRTOS] INS Task is being DELAY! dt = [%f]", &ins_dt); + VisionSend(); // 解算完成后发送视觉数据,但是当前的实现不太优雅,后续若添加硬件触发需要重新考虑结构的组织 + osDelay(1); + } +} __attribute__((noreturn)) void StartMOTORTASK(void const *argument) { diff --git a/bsp/spi/bsp_spi.c b/bsp/spi/bsp_spi.c index c607f26..b980e8e 100644 --- a/bsp/spi/bsp_spi.c +++ b/bsp/spi/bsp_spi.c @@ -4,7 +4,8 @@ /* 所有的spi instance保存于此,用于callback时判断中断来源*/ static SPIInstance *spi_instance[SPI_DEVICE_CNT] = {NULL}; -static uint8_t idx = 0; // 配合中断以及初始化 +static uint8_t idx = 0; // 配合中断以及初始化 +uint8_t SPIDeviceOnGoing[SPI_DEVICE_CNT] = {1}; // 用于判断当前spi是否正在传输,防止多个模块同时使用一个spi总线 (0: 正在传输, 1: 未传输) SPIInstance *SPIRegister(SPI_Init_Config_s *conf) { @@ -20,7 +21,19 @@ SPIInstance *SPIRegister(SPI_Init_Config_s *conf) instance->spi_work_mode = conf->spi_work_mode; instance->callback = conf->callback; instance->id = conf->id; - + if (instance->spi_handle->Instance == SPI1) + { + instance->cs_pin_state = &SPIDeviceOnGoing[0]; + } + else if (instance->spi_handle->Instance == SPI2) + { + instance->cs_pin_state = &SPIDeviceOnGoing[1]; + } + else + { + while (1) + ; + } spi_instance[idx++] = instance; return instance; } @@ -78,11 +91,28 @@ void SPIRecv(SPIInstance *spi_ins, uint8_t *ptr_data, uint8_t len) void SPITransRecv(SPIInstance *spi_ins, uint8_t *ptr_data_rx, uint8_t *ptr_data_tx, uint8_t len) { + // 用于稍后回调使用,请保证ptr_data_rx在回调函数被调用之前仍然在作用域内,否则析构之后的行为是未定义的!!! spi_ins->rx_size = len; spi_ins->rx_buffer = ptr_data_rx; + // 等待上一次传输完成 + if (spi_ins->spi_handle->Instance == SPI1) + { + while (!SPIDeviceOnGoing[0]) + { + }; + } + else if (spi_ins->spi_handle->Instance == SPI2) + { + while (!SPIDeviceOnGoing[1]) + { + }; + } // 拉低片选,开始传输 HAL_GPIO_WritePin(spi_ins->GPIOx, spi_ins->cs_pin, GPIO_PIN_RESET); + *spi_ins->cs_pin_state = + spi_ins->CS_State = + HAL_GPIO_ReadPin(spi_ins->GPIOx, spi_ins->cs_pin); switch (spi_ins->spi_work_mode) { case SPI_DMA_MODE: @@ -95,6 +125,9 @@ void SPITransRecv(SPIInstance *spi_ins, uint8_t *ptr_data_rx, uint8_t *ptr_data_ HAL_SPI_TransmitReceive(spi_ins->spi_handle, ptr_data_tx, ptr_data_rx, len, 1000); // 默认50ms超时 // 阻塞模式不会调用回调函数,传输完成后直接拉高片选结束 HAL_GPIO_WritePin(spi_ins->GPIOx, spi_ins->cs_pin, GPIO_PIN_SET); + *spi_ins->cs_pin_state = + spi_ins->CS_State = + HAL_GPIO_ReadPin(spi_ins->GPIOx, spi_ins->cs_pin); break; default: while (1) @@ -130,6 +163,9 @@ void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) { // 先拉高片选,结束传输,在判断是否有回调函数,如果有则调用回调函数 HAL_GPIO_WritePin(spi_instance[i]->GPIOx, spi_instance[i]->cs_pin, GPIO_PIN_SET); + *spi_instance[i]->cs_pin_state = + spi_instance[i]->CS_State = + HAL_GPIO_ReadPin(spi_instance[i]->GPIOx, spi_instance[i]->cs_pin); // @todo 后续添加holdon模式,由用户自行决定何时释放片选,允许进行连续传输 if (spi_instance[i]->callback != NULL) // 回调函数不为空, 则调用回调函数 spi_instance[i]->callback(spi_instance[i]); diff --git a/bsp/spi/bsp_spi.h b/bsp/spi/bsp_spi.h index 75e6b61..e365fb6 100644 --- a/bsp/spi/bsp_spi.h +++ b/bsp/spi/bsp_spi.h @@ -24,7 +24,8 @@ typedef struct spi_ins_temp SPI_TXRX_MODE_e spi_work_mode; // 传输工作模式 uint8_t rx_size; // 本次接收的数据长度 uint8_t *rx_buffer; // 本次接收的数据缓冲区 - + uint8_t CS_State; // 片选信号状态,用于中断模式下的片选控制 + uint8_t * cs_pin_state; // 片选信号状态,用于中断模式下的片选控制 void (*callback)(struct spi_ins_temp *); // 接收回调函数 void *id; // 模块指针 } SPIInstance; diff --git a/modules/BMI088/bmi088.c b/modules/BMI088/bmi088.c index 4729b29..e38e8c2 100644 --- a/modules/BMI088/bmi088.c +++ b/modules/BMI088/bmi088.c @@ -4,6 +4,7 @@ #include "daemon.h" static DaemonInstance *bmi088_daemon_instance; + // ---------------------------以下私有函数,用于读写BMI088寄存器封装,blocking--------------------------------// /** * @brief 读取BMI088寄存器Accel. BMI088要求在不释放CS的情况下连续读取 @@ -42,12 +43,9 @@ static void BMI088GyroRead(BMI088Instance *bmi088, uint8_t reg, uint8_t *dataptr // 一次读取最多6个字节,加上一个dummy data ,第一个字节的第一个位是读写位,1为读,0为写,1-7bit是寄存器地址 static uint8_t tx[7] = {0x80}; // 读取,第一个字节为0x80 | reg ,之后是dummy data static uint8_t rx[7]; // 第一个是dummy data,第三个开始是真正的数据 + tx[0] = 0x80 | reg; - //SPITransRecv(bmi088->spi_gyro, rx, tx, len + 1); - do - { - SPITransRecv(bmi088->spi_gyro, rx, tx, len + 1); - }while (rx[1] == 0 && rx[2] == 128 && rx[6] == 129); //@todo我也不知道哪来的错误帧 先这样吧。。。。。 + SPITransRecv(bmi088->spi_gyro, rx, tx, len + 1); memcpy(dataptr, rx + 1, len); // @todo : memcpy有额外开销,后续可以考虑优化,在SPI中加入接口或模式,使得在一次传输结束后不释放CS,直接接着传输 } @@ -97,7 +95,7 @@ static uint8_t BMI088_Accel_Init_Table[BMI088_WRITE_ACCEL_REG_NUM][3] = static uint8_t BMI088_Gyro_Init_Table[BMI088_WRITE_GYRO_REG_NUM][3] = { {BMI088_GYRO_RANGE, BMI088_GYRO_2000, BMI088_GYRO_RANGE_ERROR}, - {BMI088_GYRO_BANDWIDTH, BMI088_GYRO_2000_230_HZ | BMI088_GYRO_BANDWIDTH_MUST_Set, BMI088_GYRO_BANDWIDTH_ERROR}, + {BMI088_GYRO_BANDWIDTH, BMI088_GYRO_1000_116_HZ | BMI088_GYRO_BANDWIDTH_MUST_Set, BMI088_GYRO_BANDWIDTH_ERROR}, {BMI088_GYRO_LPM1, BMI088_GYRO_NORMAL_MODE, BMI088_GYRO_LPM1_ERROR}, {BMI088_GYRO_CTRL, BMI088_DRDY_ON, BMI088_GYRO_CTRL_ERROR}, {BMI088_GYRO_INT3_INT4_IO_CONF, BMI088_GYRO_INT3_GPIO_PP | BMI088_GYRO_INT3_GPIO_LOW, BMI088_GYRO_INT3_INT4_IO_CONF_ERROR}, @@ -224,18 +222,18 @@ static void BMI088AccINTCallback(GPIOInstance *gpio) static void BMI088GyroINTCallback(GPIOInstance *gpio) { + static BMI088Instance *bmi088; static uint8_t buf[6] = {0}; // 最多读取6个byte(gyro/acc,temp是2) bmi088 = (BMI088Instance *)(gpio->id); bmi088->update_flag.imu_ready = 1; bmi088->update_flag.gyro = 1; + uint8_t whoami_check = 0; + //do{BMI088GyroRead(bmi088, BMI088_GYRO_CHIP_ID, &whoami_check, 1);}while(whoami_check != BMI088_GYRO_CHIP_ID_VALUE); + BMI088GyroRead(bmi088, BMI088_GYRO_X_L, buf, 6); for (uint8_t i = 0; i < 3; i++) bmi088->gyro[i] = bmi088->BMI088_GYRO_SEN * (float)(int16_t)(((buf[2 * i + 1]) << 8) | buf[2 * i]); - if(bmi088->gyro[0] < -20) - { - bmi088->update_flag.temp = 1; - } // 启动陀螺仪数据读取,并转换为实际值 // 读取完毕会调用BMI088GyroSPIFinishCallback } @@ -277,13 +275,15 @@ uint8_t BMI088Acquire(BMI088Instance *bmi088, BMI088_Data_t *data_store) { memcpy(data_store->acc,bmi088->acc,3*sizeof(float)); bmi088->update_flag.acc = 0; + bmi088->update_flag.imu_ready = 0; } if(bmi088->update_flag.gyro == 1) { memcpy(data_store->gyro,bmi088->gyro,3*sizeof(float)); bmi088->update_flag.gyro = 0; + bmi088->update_flag.imu_ready = 0; } - bmi088->update_flag.imu_ready = 0; + return 1; }