添加了大量调试log,新增了dwt计时宏,增加了USB软件复位防止主控复位后上位机无法连接usb

This commit is contained in:
NeoZng 2023-06-22 21:52:46 +08:00
parent ea6163a48d
commit 4a45331d31
31 changed files with 247 additions and 275 deletions

View File

@ -52,6 +52,7 @@ void MemManage_Handler(void);
void BusFault_Handler(void); void BusFault_Handler(void);
void UsageFault_Handler(void); void UsageFault_Handler(void);
void DebugMon_Handler(void); void DebugMon_Handler(void);
void FLASH_IRQHandler(void);
void EXTI3_IRQHandler(void); void EXTI3_IRQHandler(void);
void EXTI4_IRQHandler(void); void EXTI4_IRQHandler(void);
void DMA1_Stream1_IRQHandler(void); void DMA1_Stream1_IRQHandler(void);

View File

@ -123,9 +123,9 @@ void MX_FREERTOS_Init(void)
void StartDefaultTask(void const *argument) void StartDefaultTask(void const *argument)
{ {
/* init code for USB_DEVICE */ /* init code for USB_DEVICE */
MX_USB_DEVICE_Init(); // USB??? MX_USB_DEVICE_Init(); // 默认usb启动任务的位置
/* USER CODE BEGIN StartDefaultTask */ /* USER CODE BEGIN StartDefaultTask */
vTaskDelete(NULL); // ??????,????CPU vTaskDelete(NULL); // 避免空置和切换占用cpu
/* USER CODE END StartDefaultTask */ /* USER CODE END StartDefaultTask */
} }

View File

@ -73,6 +73,11 @@ void HAL_MspInit(void)
/* PendSV_IRQn interrupt configuration */ /* PendSV_IRQn interrupt configuration */
HAL_NVIC_SetPriority(PendSV_IRQn, 15, 0); HAL_NVIC_SetPriority(PendSV_IRQn, 15, 0);
/* Peripheral interrupt init */
/* FLASH_IRQn interrupt configuration */
HAL_NVIC_SetPriority(FLASH_IRQn, 6, 0);
HAL_NVIC_EnableIRQ(FLASH_IRQn);
/* USER CODE BEGIN MspInit 1 */ /* USER CODE BEGIN MspInit 1 */
/* USER CODE END MspInit 1 */ /* USER CODE END MspInit 1 */

View File

@ -183,6 +183,20 @@ void DebugMon_Handler(void)
/* please refer to the startup file (startup_stm32f4xx.s). */ /* please refer to the startup file (startup_stm32f4xx.s). */
/******************************************************************************/ /******************************************************************************/
/**
* @brief This function handles Flash global interrupt.
*/
void FLASH_IRQHandler(void)
{
/* USER CODE BEGIN FLASH_IRQn 0 */
/* USER CODE END FLASH_IRQn 0 */
HAL_FLASH_IRQHandler();
/* USER CODE BEGIN FLASH_IRQn 1 */
/* USER CODE END FLASH_IRQn 1 */
}
/** /**
* @brief This function handles EXTI line3 interrupt. * @brief This function handles EXTI line3 interrupt.
*/ */

View File

@ -27,7 +27,7 @@
#include "usbd_cdc.h" #include "usbd_cdc.h"
/* USER CODE BEGIN Includes */ /* USER CODE BEGIN Includes */
#include "bsp_dwt.h"
/* USER CODE END Includes */ /* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/ /* Private typedef -----------------------------------------------------------*/
@ -95,7 +95,11 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef* pcdHandle)
HAL_NVIC_SetPriority(OTG_FS_IRQn, 5, 0); HAL_NVIC_SetPriority(OTG_FS_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(OTG_FS_IRQn); HAL_NVIC_EnableIRQ(OTG_FS_IRQn);
/* USER CODE BEGIN USB_OTG_FS_MspInit 1 */ /* USER CODE BEGIN USB_OTG_FS_MspInit 1 */
// 上电后重新枚举usb设备
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_12, GPIO_PIN_RESET);
DWT_Delay(100);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_12, GPIO_PIN_RESET);
DWT_Delay(100);
/* USER CODE END USB_OTG_FS_MspInit 1 */ /* USER CODE END USB_OTG_FS_MspInit 1 */
} }
} }

View File

@ -8,6 +8,9 @@
#include "message_center.h" #include "message_center.h"
#include "general_def.h" #include "general_def.h"
#include "dji_motor.h" #include "dji_motor.h"
// bsp
#include "bsp_dwt.h"
#include "bsp_log.h"
// 私有宏,自动将编码器转换成角度值 // 私有宏,自动将编码器转换成角度值
#define YAW_ALIGN_ANGLE (YAW_CHASSIS_ALIGN_ECD * ECD_ANGLE_COEF_DJI) // 对齐时的角度,0-360 #define YAW_ALIGN_ANGLE (YAW_CHASSIS_ALIGN_ECD * ECD_ANGLE_COEF_DJI) // 对齐时的角度,0-360
@ -266,12 +269,14 @@ static void EmergencyHandler()
shoot_cmd_send.shoot_mode = SHOOT_OFF; shoot_cmd_send.shoot_mode = SHOOT_OFF;
shoot_cmd_send.friction_mode = FRICTION_OFF; shoot_cmd_send.friction_mode = FRICTION_OFF;
shoot_cmd_send.load_mode = LOAD_STOP; shoot_cmd_send.load_mode = LOAD_STOP;
LOGERROR("[CMD] emergency stop!");
} }
// 遥控器右侧开关为[上],恢复正常运行 // 遥控器右侧开关为[上],恢复正常运行
if (switch_is_up(rc_data[TEMP].rc.switch_right)) if (switch_is_up(rc_data[TEMP].rc.switch_right))
{ {
robot_state = ROBOT_READY; robot_state = ROBOT_READY;
shoot_cmd_send.shoot_mode = SHOOT_ON; shoot_cmd_send.shoot_mode = SHOOT_ON;
LOGINFO("[CMD] reinstate, robot ready");
} }
} }

View File

@ -13,6 +13,8 @@
#include "daemon.h" #include "daemon.h"
#include "HT04.h" #include "HT04.h"
#include "bsp_log.h"
osThreadId insTaskHandle; osThreadId insTaskHandle;
osThreadId robotTaskHandle; osThreadId robotTaskHandle;
osThreadId motorTaskHandle; osThreadId motorTaskHandle;
@ -54,12 +56,15 @@ void StartINSTASK(void const *argument)
{ {
static float ins_start, ins_dt; static float ins_start, ins_dt;
INS_Init(); // 确保BMI088被正确初始化. INS_Init(); // 确保BMI088被正确初始化.
LOGINFO("[freeRTOS] INS Task Start");
while (1) while (1)
{ {
// 1kHz // 1kHz
ins_start = DWT_GetTimeline_ms(); ins_start = DWT_GetTimeline_ms();
INS_Task(); INS_Task();
ins_dt = DWT_GetTimeline_ms() - ins_start; ins_dt = DWT_GetTimeline_ms() - ins_start;
if (ins_dt > 1)
LOGERROR("[freeRTOS] INS Task is being DELAY! dt = [%f]", &ins_dt);
VisionSend(); // 解算完成后发送视觉数据,但是当前的实现不太优雅,后续若添加硬件触发需要重新考虑结构的组织 VisionSend(); // 解算完成后发送视觉数据,但是当前的实现不太优雅,后续若添加硬件触发需要重新考虑结构的组织
osDelay(1); osDelay(1);
} }
@ -68,21 +73,30 @@ void StartINSTASK(void const *argument)
void StartMOTORTASK(void const *argument) void StartMOTORTASK(void const *argument)
{ {
static float motor_dt, motor_start; static float motor_dt, motor_start;
LOGINFO("[freeRTOS] MOTOR Task Start");
while (1) while (1)
{ {
motor_start = DWT_GetTimeline_ms(); motor_start = DWT_GetTimeline_ms();
MotorControlTask(); MotorControlTask();
motor_dt = DWT_GetTimeline_ms() - motor_start; motor_dt = DWT_GetTimeline_ms() - motor_start;
if (motor_dt > 1)
LOGERROR("[freeRTOS] MOTOR Task is being DELAY! dt = [%f]", &motor_dt);
osDelay(1); osDelay(1);
} }
} }
void StartDAEMONTASK(void const *argument) void StartDAEMONTASK(void const *argument)
{ {
static float daemon_dt, daemon_start;
LOGINFO("[freeRTOS] Daemon Task Start");
while (1) while (1)
{ {
// 100Hz // 100Hz
daemon_start = DWT_GetTimeline_ms();
DaemonTask(); DaemonTask();
daemon_dt = DWT_GetTimeline_ms() - daemon_start;
if (daemon_dt > 10)
LOGERROR("[freeRTOS] Daemon Task is being DELAY! dt = [%f]", &daemon_dt);
osDelay(10); osDelay(10);
} }
} }
@ -90,19 +104,24 @@ void StartDAEMONTASK(void const *argument)
void StartROBOTTASK(void const *argument) void StartROBOTTASK(void const *argument)
{ {
static float robot_dt, robot_start; static float robot_dt, robot_start;
LOGINFO("[freeRTOS] ROBOT core Task Start");
// 200Hz-500Hz,若有额外的控制任务如平衡步兵可能需要提升至1kHz // 200Hz-500Hz,若有额外的控制任务如平衡步兵可能需要提升至1kHz
while (1) while (1)
{ {
robot_start = DWT_GetTimeline_ms(); robot_start = DWT_GetTimeline_ms();
RobotTask(); RobotTask();
robot_dt = DWT_GetTimeline_ms() - robot_start; robot_dt = DWT_GetTimeline_ms() - robot_start;
if (robot_dt > 5)
LOGERROR("[freeRTOS] ROBOT core Task is being DELAY! dt = [%f]", &robot_dt);
osDelay(5); osDelay(5);
} }
} }
void StartUITASK(void const *argument) void StartUITASK(void const *argument)
{ {
LOGINFO("[freeRTOS] UI Task Start");
MyUIInit(); MyUIInit();
LOGINFO("[freeRTOS] UI Init Done, communication with ref has established");
while (1) while (1)
{ {
// 每给裁判系统发送一包数据会挂起一次,详见UITask函数的refereeSend() // 每给裁判系统发送一包数据会挂起一次,详见UITask函数的refereeSend()

View File

@ -308,6 +308,7 @@ NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:fals
NVIC.EXTI3_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true\:true NVIC.EXTI3_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true\:true
NVIC.EXTI4_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true NVIC.EXTI4_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true
NVIC.EXTI9_5_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true NVIC.EXTI9_5_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true
NVIC.FLASH_IRQn=true\:6\:0\:true\:false\:true\:true\:true\:true\:true
NVIC.ForceEnableDMAVector=true NVIC.ForceEnableDMAVector=true
NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false
NVIC.I2C2_ER_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true NVIC.I2C2_ER_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true

View File

@ -65,15 +65,20 @@ CANInstance *CANRegister(CAN_Init_Config_s *config)
if (!idx) if (!idx)
{ {
CANServiceInit(); // 第一次注册,先进行硬件初始化 CANServiceInit(); // 第一次注册,先进行硬件初始化
LOGINFO("[bsp_can] CAN Service Init");
} }
if (idx >= CAN_MX_REGISTER_CNT) // 超过最大实例数 if (idx >= CAN_MX_REGISTER_CNT) // 超过最大实例数
{
while (1) while (1)
; LOGERROR("[bsp_can] CAN instance exceeded MAX num, consider balance the load of CAN bus");
}
for (size_t i = 0; i < idx; i++) for (size_t i = 0; i < idx; i++)
{ // 重复注册 | id重复 { // 重复注册 | id重复
if (can_instance[i]->rx_id == config->rx_id && can_instance[i]->can_handle == config->can_handle) if (can_instance[i]->rx_id == config->rx_id && can_instance[i]->can_handle == config->can_handle)
{
while (1) while (1)
; LOGERROR("[}bsp_can] CAN id crash ,tx [%d] or rx [%d] already registered", &config->tx_id, &config->rx_id);
}
} }
CANInstance *instance = (CANInstance *)malloc(sizeof(CANInstance)); // 分配空间 CANInstance *instance = (CANInstance *)malloc(sizeof(CANInstance)); // 分配空间
@ -107,7 +112,7 @@ uint8_t CANTransmit(CANInstance *_instance, float timeout)
{ {
if (DWT_GetTimeline_ms() - dwt_start > timeout) // 超时 if (DWT_GetTimeline_ms() - dwt_start > timeout) // 超时
{ {
LOGWARNING("CAN BUSY sending! cnt:%d", busy_count); LOGWARNING("[bsp_can] CAN MAILbox full! failed to add msg to mailbox. Cnt [%d]", busy_count);
busy_count++; busy_count++;
return 0; return 0;
} }
@ -116,7 +121,7 @@ uint8_t CANTransmit(CANInstance *_instance, float timeout)
// tx_mailbox会保存实际填入了这一帧消息的邮箱,但是知道是哪个邮箱发的似乎也没啥用 // tx_mailbox会保存实际填入了这一帧消息的邮箱,但是知道是哪个邮箱发的似乎也没啥用
if (HAL_CAN_AddTxMessage(_instance->can_handle, &_instance->txconf, _instance->tx_buff, &_instance->tx_mailbox)) if (HAL_CAN_AddTxMessage(_instance->can_handle, &_instance->txconf, _instance->tx_buff, &_instance->tx_mailbox))
{ {
LOGWARNING("CAN BUSY bus! cnt:%d", busy_count); LOGWARNING("[bsp_can] CAN bus BUS! cnt:%d", busy_count);
busy_count++; busy_count++;
return 0; return 0;
} }
@ -125,9 +130,10 @@ uint8_t CANTransmit(CANInstance *_instance, float timeout)
void CANSetDLC(CANInstance *_instance, uint8_t length) void CANSetDLC(CANInstance *_instance, uint8_t length)
{ {
// 发送长度错误!检查调用参数是否出错,或出现野指针/越界访问
if (length > 8 || length == 0) // 安全检查 if (length > 8 || length == 0) // 安全检查
while (1) while (1)
; // 发送长度错误!检查调用参数是否出错,或出现野指针/越界访问 LOGERROR("[bsp_can] CAN DLC error! check your code or wild pointer");
_instance->txconf.DLC = length; _instance->txconf.DLC = length;
} }

View File

@ -22,7 +22,7 @@ static osMutexId DWT_MUTEX;
* @brief ,DWT CYCCNT寄存器是否溢出,CYCCNT_RountCount * @brief ,DWT CYCCNT寄存器是否溢出,CYCCNT_RountCount
* @attention * @attention
* *
* @todo dwt的时间更新单独设置一个任务 * @todo dwt的时间更新单独设置一个任务?
* ,使dwt的初衷是定时不被中断/, * ,使dwt的初衷是定时不被中断/,
* *
*/ */
@ -131,6 +131,5 @@ void DWT_Delay(float Delay)
float wait = Delay; float wait = Delay;
while ((DWT->CYCCNT - tickstart) < wait * (float)CPU_FREQ_Hz) while ((DWT->CYCCNT - tickstart) < wait * (float)CPU_FREQ_Hz)
{ ;
}
} }

View File

@ -2,7 +2,8 @@
****************************************************************************** ******************************************************************************
* @file bsp_dwt.h * @file bsp_dwt.h
* @author Wang Hongxi * @author Wang Hongxi
* @version V1.1.0 * @author modified by NeoZng
* @version V1.2.0
* @date 2022/3/8 * @date 2022/3/8
* @brief * @brief
****************************************************************************** ******************************************************************************
@ -15,6 +16,7 @@
#include "main.h" #include "main.h"
#include "stdint.h" #include "stdint.h"
#include "bsp_log.h"
typedef struct typedef struct
{ {
@ -23,6 +25,19 @@ typedef struct
uint16_t us; uint16_t us;
} DWT_Time_t; } DWT_Time_t;
/**
* @brief ,/s,float类型
* float类型的变量,
* RTT打印到日志终端,dt变量添加到查看
*/
#define TIME_ELAPSE(dt, code) \
do \
{ \
float tstart = DWT_GetTimeline_s(); \
code; \
dt = DWT_GetTimeline_s() - tstart; \
LOGINFO("[DWT] " #dt " = %f s\r\n", dt); \
} while (0)
/** /**
* @brief DWT,CPU频率,MHz * @brief DWT,CPU频率,MHz
@ -83,6 +98,4 @@ void DWT_Delay(float Delay);
*/ */
void DWT_SysTimeUpdate(void); void DWT_SysTimeUpdate(void);
#endif /* BSP_DWT_H_ */ #endif /* BSP_DWT_H_ */

View File

@ -2,8 +2,6 @@
DWT是stm32内部的一个"隐藏资源",他的用途是给下载器提供准确的定时,从而为调试信息加上时间戳.并在固定的时间间隔将调试数据发送到你的xxlink上. DWT是stm32内部的一个"隐藏资源",他的用途是给下载器提供准确的定时,从而为调试信息加上时间戳.并在固定的时间间隔将调试数据发送到你的xxlink上.
## 常用功能 ## 常用功能
### 计算两次进入同一个函数的时间间隔 ### 计算两次进入同一个函数的时间间隔
@ -28,3 +26,29 @@ for(uint8_t i=0;i<10;i++)
end = DWT_DetTimeline_ms()-start; end = DWT_DetTimeline_ms()-start;
``` ```
我们还提供了一个宏用于调试计时:
```c
#define TIME_ELAPSE(dt, code) \
do \
{ \
float tstart = DWT_GetTimeline_s(); \
code; \
dt = DWT_GetTimeline_s() - tstart; \
LOGINFO("[DWT] " #dt " = %f s\r\n", dt); \
} while (0)
```
传入一个float类型的变量,并将你要执行的代码写入第二个参数:
```c
static float my_func_dt;
TIME_ELAPSE(my_func_dt,
Function1(vara);
Function2(some, var);
Function3(your,param);
// something more
);
// my_func_dt can be used for other purpose then;
```

View File

@ -36,11 +36,11 @@ void BSPLogInit();
/* 有颜色格式日志输出,建议使用这些宏来输出日志 */ /* 有颜色格式日志输出,建议使用这些宏来输出日志 */
// information level // information level
#define LOGINFO(format,...) LOG_PROTO("I", RTT_CTRL_TEXT_BRIGHT_GREEN , format, ##__VA_ARGS__) #define LOGINFO(format,...) LOG_PROTO("I:", RTT_CTRL_TEXT_BRIGHT_GREEN , format, ##__VA_ARGS__)
// warning level // warning level
#define LOGWARNING(format,...) LOG_PROTO("W", RTT_CTRL_TEXT_BRIGHT_YELLOW, format, ##__VA_ARGS__) #define LOGWARNING(format,...) LOG_PROTO("W:", RTT_CTRL_TEXT_BRIGHT_YELLOW, format, ##__VA_ARGS__)
// error level // error level
#define LOGERROR(format,...) LOG_PROTO("E", RTT_CTRL_TEXT_BRIGHT_RED , format, ##__VA_ARGS__) #define LOGERROR(format,...) LOG_PROTO("E:", RTT_CTRL_TEXT_BRIGHT_RED , format, ##__VA_ARGS__)
/** /**
* @brief segger RTT打印日志,,printf. * @brief segger RTT打印日志,,printf.

View File

@ -5,7 +5,6 @@
> TODO: > TODO:
> >
> 1. 在未接入调试器的时候将日志写入flash中并提供接口读取 > 1. 在未接入调试器的时候将日志写入flash中并提供接口读取
> 2. 增加日志分级提供info、warning、error三个等级的日志
## 使用说明 ## 使用说明

View File

@ -9,6 +9,7 @@
* *
*/ */
#include "bsp_usart.h" #include "bsp_usart.h"
#include "bsp_log.h"
#include "stdlib.h" #include "stdlib.h"
#include "memory.h" #include "memory.h"
@ -38,7 +39,13 @@ USARTInstance *USARTRegister(USART_Init_Config_s *init_config)
{ {
if (idx >= DEVICE_USART_CNT) // 超过最大实例数 if (idx >= DEVICE_USART_CNT) // 超过最大实例数
while (1) while (1)
; LOGERROR("[bsp_usart] USART exceed max instance count!");
for (uint8_t i = 0; i < idx; i++) // 检查是否已经注册过
if (usart_instance[i]->usart_handle == init_config->usart_handle)
while (1)
LOGERROR("[bsp_usart] USART instance already registered!");
USARTInstance *instance = (USARTInstance *)malloc(sizeof(USARTInstance)); USARTInstance *instance = (USARTInstance *)malloc(sizeof(USARTInstance));
memset(instance, 0, sizeof(USARTInstance)); memset(instance, 0, sizeof(USARTInstance));
@ -75,14 +82,10 @@ void USARTSend(USARTInstance *_instance, uint8_t *send_buf, uint16_t send_size,
/* 串口发送时,gstate会被设为BUSY_TX */ /* 串口发送时,gstate会被设为BUSY_TX */
uint8_t USARTIsReady(USARTInstance *_instance) uint8_t USARTIsReady(USARTInstance *_instance)
{ {
if(_instance->usart_handle->gState | HAL_UART_STATE_BUSY_TX) if (_instance->usart_handle->gState | HAL_UART_STATE_BUSY_TX)
{
return 0; return 0;
}
else else
{
return 1; return 1;
}
} }
/** /**
@ -129,6 +132,7 @@ void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{ {
HAL_UARTEx_ReceiveToIdle_DMA(usart_instance[i]->usart_handle, usart_instance[i]->recv_buff, usart_instance[i]->recv_buff_size); HAL_UARTEx_ReceiveToIdle_DMA(usart_instance[i]->usart_handle, usart_instance[i]->recv_buff, usart_instance[i]->recv_buff_size);
__HAL_DMA_DISABLE_IT(usart_instance[i]->usart_handle->hdmarx, DMA_IT_HT); __HAL_DMA_DISABLE_IT(usart_instance[i]->usart_handle->hdmarx, DMA_IT_HT);
LOGWARNING("[bsp_usart] USART error callback triggered, instance idx [%d]", i);
return; return;
} }
} }

View File

@ -11,9 +11,9 @@
需要在串口实例下设定接收的数据包的长度,实例对应的串口硬件(通过`UART_HandleTypeDef`指定,如`&huart1`),解析接收数据对应的回调函数这三个参数。然后,调用`USARTRegister()`并传入配置好的`usart_instance`指针即可。 需要在串口实例下设定接收的数据包的长度,实例对应的串口硬件(通过`UART_HandleTypeDef`指定,如`&huart1`),解析接收数据对应的回调函数这三个参数。然后,调用`USARTRegister()`并传入配置好的`usart_instance`指针即可。
若要发送数据,调用`USARTSend()`。注意buffsize务必小于buff的大小否则造成指针越界后果未知。 若要发送数据,调用`USARTSend()`。注意buffsize务必小于你创建的buff的大小否则造成指针越界后果未知。
串口硬件收到数据时,会将其存入`usart_instance.recv_buff[]`中,当收到完整一包数据,会调用设定的回调函数`module_callback`(即你提供的解析函数)。在此函数中,你可以通过`usart_instance.recv_buff[]`访问串口收到的数据。 串口硬件收到数据时,会将其存入`usart_instance.recv_buff[]`中,当收到完整一包数据,会调用设定的回调函数`module_callback`(即你注册时提供的解析函数)。在此函数中,你可以通过`usart_instance.recv_buff[]`访问串口收到的数据。
## 代码结构 ## 代码结构

View File

@ -11,16 +11,17 @@
#include "bsp_usb.h" #include "bsp_usb.h"
#include "bsp_log.h" #include "bsp_log.h"
#include "bsp_dwt.h"
static uint8_t *bsp_usb_rx_buffer; // 接收到的数据会被放在这里,buffer size为2048 static uint8_t *bsp_usb_rx_buffer; // 接收到的数据会被放在这里,buffer size为2048
// 注意usb单个数据包(Full speed模式下)最大为64byte,超出可能会出现丢包情况 // 注意usb单个数据包(Full speed模式下)最大为64byte,超出可能会出现丢包情况
uint8_t *USBInit(USB_Init_Config_s usb_conf) uint8_t *USBInit(USB_Init_Config_s usb_conf)
{ {
// 上电后重新枚举usb设备 // usb的软件复位(模拟拔插)在usbd_conf.c中的HAL_PCD_MspInit()中
LOGINFO("USB init success");
bsp_usb_rx_buffer = CDCInitRxbufferNcallback(usb_conf.tx_cbk, usb_conf.rx_cbk); // 获取接收数据指针 bsp_usb_rx_buffer = CDCInitRxbufferNcallback(usb_conf.tx_cbk, usb_conf.rx_cbk); // 获取接收数据指针
// usb的接收回调函数会在这里被设置,并将数据保存在bsp_usb_rx_buffer中 // usb的接收回调函数会在这里被设置,并将数据保存在bsp_usb_rx_buffer中
LOGINFO("USB init success");
return bsp_usb_rx_buffer; return bsp_usb_rx_buffer;
} }

View File

@ -55,9 +55,7 @@ static void BMI088GyroRead(BMI088Instance *bmi088, uint8_t reg, uint8_t *dataptr
*/ */
static void BMI088AccelWriteSingleReg(BMI088Instance *bmi088, uint8_t reg, uint8_t data) static void BMI088AccelWriteSingleReg(BMI088Instance *bmi088, uint8_t reg, uint8_t data)
{ {
static uint8_t tx[2]; uint8_t tx[2] = {reg, data};
tx[0] = reg;
tx[1] = data;
SPITransmit(bmi088->spi_acc, tx, 2); SPITransmit(bmi088->spi_acc, tx, 2);
} }
@ -71,17 +69,15 @@ static void BMI088AccelWriteSingleReg(BMI088Instance *bmi088, uint8_t reg, uint8
*/ */
static void BMI088GyroWriteSingleReg(BMI088Instance *bmi088, uint8_t reg, uint8_t data) static void BMI088GyroWriteSingleReg(BMI088Instance *bmi088, uint8_t reg, uint8_t data)
{ {
static uint8_t tx[2]; uint8_t tx[2] = {reg, data};
tx[0] = reg;
tx[1] = data;
SPITransmit(bmi088->spi_gyro, tx, 2); SPITransmit(bmi088->spi_gyro, tx, 2);
} }
// -------------------------以上为私有函数,封装了BMI088寄存器读写函数,blocking--------------------------------// // -------------------------以上为私有函数,封装了BMI088寄存器读写函数,blocking--------------------------------//
// -------------------------以下为私有函数,用于初始化BMI088acc和gyro的硬件和配置--------------------------------// // -------------------------以下为私有函数,用于初始化BMI088acc和gyro的硬件和配置--------------------------------//
#define REG 0 #define BMI088REG 0
#define DATA 1 #define BMI088DATA 1
#define ERROR 2 #define BMI088ERROR 2
// BMI088初始化配置数组for accel,第一列为reg地址,第二列为写入的配置值,第三列为错误码(如果出错) // BMI088初始化配置数组for accel,第一列为reg地址,第二列为写入的配置值,第三列为错误码(如果出错)
static uint8_t BMI088_Accel_Init_Table[BMI088_WRITE_ACCEL_REG_NUM][3] = static uint8_t BMI088_Accel_Init_Table[BMI088_WRITE_ACCEL_REG_NUM][3] =
{ {
@ -106,7 +102,7 @@ static uint8_t BMI088_Gyro_Init_Table[BMI088_WRITE_GYRO_REG_NUM][3] =
* @brief BMI088加速度计, * @brief BMI088加速度计,
* *
* @param bmi088 BMI088实例 * @param bmi088 BMI088实例
* @return uint8_t ERROR CODE if any problems here * @return uint8_t BMI088ERROR CODE if any problems here
*/ */
static uint8_t BMI088AccelInit(BMI088Instance *bmi088) static uint8_t BMI088AccelInit(BMI088Instance *bmi088)
{ {
@ -130,14 +126,14 @@ static uint8_t BMI088AccelInit(BMI088Instance *bmi088)
// 使用sizeof而不是magic number,这样如果修改了数组大小,不用修改这里的代码;或者使用宏定义 // 使用sizeof而不是magic number,这样如果修改了数组大小,不用修改这里的代码;或者使用宏定义
for (uint8_t i = 0; i < sizeof(BMI088_Accel_Init_Table) / sizeof(BMI088_Accel_Init_Table[0]); i++) for (uint8_t i = 0; i < sizeof(BMI088_Accel_Init_Table) / sizeof(BMI088_Accel_Init_Table[0]); i++)
{ {
reg = BMI088_Accel_Init_Table[i][REG]; reg = BMI088_Accel_Init_Table[i][BMI088REG];
data = BMI088_Accel_Init_Table[i][DATA]; data = BMI088_Accel_Init_Table[i][BMI088DATA];
BMI088AccelWriteSingleReg(bmi088, reg, data); // 写入寄存器 BMI088AccelWriteSingleReg(bmi088, reg, data); // 写入寄存器
DWT_Delay(0.01); DWT_Delay(0.01);
BMI088AccelRead(bmi088, reg, &data, 1); // 写完之后立刻读回检查 BMI088AccelRead(bmi088, reg, &data, 1); // 写完之后立刻读回检查
DWT_Delay(0.01); DWT_Delay(0.01);
if (data != BMI088_Accel_Init_Table[i][DATA]) if (data != BMI088_Accel_Init_Table[i][BMI088DATA])
error |= BMI088_Accel_Init_Table[i][ERROR]; error |= BMI088_Accel_Init_Table[i][BMI088ERROR];
//{i--;} 可以设置retry次数,如果retry次数用完了,则返回error //{i--;} 可以设置retry次数,如果retry次数用完了,则返回error
} }
return error; return error;
@ -147,7 +143,7 @@ static uint8_t BMI088AccelInit(BMI088Instance *bmi088)
* @brief BMI088陀螺仪, * @brief BMI088陀螺仪,
* *
* @param bmi088 BMI088实例 * @param bmi088 BMI088实例
* @return uint8_t ERROR CODE * @return uint8_t BMI088ERROR CODE
*/ */
static uint8_t BMI088GyroInit(BMI088Instance *bmi088) static uint8_t BMI088GyroInit(BMI088Instance *bmi088)
{ {
@ -169,14 +165,14 @@ static uint8_t BMI088GyroInit(BMI088Instance *bmi088)
// 使用sizeof而不是magic number,这样如果修改了数组大小,不用修改这里的代码;或者使用宏定义 // 使用sizeof而不是magic number,这样如果修改了数组大小,不用修改这里的代码;或者使用宏定义
for (uint8_t i = 0; i < sizeof(BMI088_Gyro_Init_Table) / sizeof(BMI088_Gyro_Init_Table[0]); i++) for (uint8_t i = 0; i < sizeof(BMI088_Gyro_Init_Table) / sizeof(BMI088_Gyro_Init_Table[0]); i++)
{ {
reg = BMI088_Gyro_Init_Table[i][REG]; reg = BMI088_Gyro_Init_Table[i][BMI088REG];
data = BMI088_Gyro_Init_Table[i][DATA]; data = BMI088_Gyro_Init_Table[i][BMI088DATA];
BMI088GyroWriteSingleReg(bmi088, reg, data); // 写入寄存器 BMI088GyroWriteSingleReg(bmi088, reg, data); // 写入寄存器
DWT_Delay(0.001); DWT_Delay(0.001);
BMI088GyroRead(bmi088, reg, &data, 1); // 写完之后立刻读回对应寄存器检查是否写入成功 BMI088GyroRead(bmi088, reg, &data, 1); // 写完之后立刻读回对应寄存器检查是否写入成功
DWT_Delay(0.001); DWT_Delay(0.001);
if (data != BMI088_Gyro_Init_Table[i][DATA]) if (data != BMI088_Gyro_Init_Table[i][BMI088DATA])
error |= BMI088_Gyro_Init_Table[i][ERROR]; error |= BMI088_Gyro_Init_Table[i][BMI088ERROR];
//{i--;} 可以设置retry次数,尝试重新写入.如果retry次数用完了,则返回error //{i--;} 可以设置retry次数,尝试重新写入.如果retry次数用完了,则返回error
} }

View File

@ -7,24 +7,24 @@
```c ```c
BMI088_Init_Config_s imu_config = { BMI088_Init_Config_s imu_config = {
.spi_acc_config={ .spi_acc_config={
.GPIOx=GPIOC, .GPIOx=GPIOA,
.GPIOx=GPIO_PIN_4, .GPIOx=GPIO_PIN_4,
.spi_handle=&hspi1, .spi_handle=&hspi1,
}, },
.spi_gyro_config={ .spi_gyro_config={
.GPIOx=GPIOC, .GPIOx=GPIOB,
.GPIOx=GPIO_PIN_4, .GPIOx=GPIO_PIN_0,
.spi_handle=&hspi1, .spi_handle=&hspi1,
}, },
.acc_int_config={ .acc_int_config={
.exti_mode=EXTI_TRIGGER_FALLING, .exti_mode=EXTI_TRIGGER_FALLING,
.GPIO_Pin=GPIO_PIN_10, .GPIO_Pin=GPIO_PIN_4,
.GPIOx=GPIOA, .GPIOx=GPIOC,
}, },
.gyro_int_config={ .gyro_int_config={
.exti_mode=EXTI_TRIGGER_FALLING, .exti_mode=EXTI_TRIGGER_FALLING,
.GPIO_Pin=GPIO_PIN_11, .GPIO_Pin=GPIO_PIN_5,
.GPIOx=GPIOA, .GPIOx=GPIOC,
}, },
.heat_pid_config={ .heat_pid_config={
.Kp=0.0f, .Kp=0.0f,

View File

@ -3,6 +3,7 @@
#include "stdlib.h" #include "stdlib.h"
#include "crc8.h" #include "crc8.h"
#include "bsp_dwt.h" #include "bsp_dwt.h"
#include "bsp_log.h"
/** /**
* @brief CAN comm的接收状态和buffer * @brief CAN comm的接收状态和buffer
@ -69,6 +70,13 @@ static void CANCommRxCallback(CANInstance *_instance)
} }
} }
static void CANCommLostCallback(void *cancomm)
{
CANCommInstance *comm = (CANCommInstance *)cancomm;
CANCommResetRx(comm);
LOGWARNING("[can_comm] can comm rx[%d] lost, reset rx state.", &comm->can_ins->rx_id);
}
CANCommInstance *CANCommInit(CANComm_Init_Config_s *comm_config) CANCommInstance *CANCommInit(CANComm_Init_Config_s *comm_config)
{ {
CANCommInstance *ins = (CANCommInstance *)malloc(sizeof(CANCommInstance)); CANCommInstance *ins = (CANCommInstance *)malloc(sizeof(CANCommInstance));

View File

@ -2,6 +2,7 @@
#include "BMI088reg.h" #include "BMI088reg.h"
#include "BMI088Middleware.h" #include "BMI088Middleware.h"
#include "bsp_dwt.h" #include "bsp_dwt.h"
#include "bsp_log.h"
#include <math.h> #include <math.h>
#warning this is a legacy support. test the new BMI088 module as soon as possible. #warning this is a legacy support. test the new BMI088 module as soon as possible.
@ -129,7 +130,7 @@ void Calibrate_MPU_Offset(IMU_Data_t *bmi088)
startTime = DWT_GetTimeline_s(); startTime = DWT_GetTimeline_s();
do do
{ {
if (DWT_GetTimeline_s() - startTime > 10) if (DWT_GetTimeline_s() - startTime > 12)
{ {
// <20><>???? // <20><>????
bmi088->GyroOffset[0] = GxOFFSET; bmi088->GyroOffset[0] = GxOFFSET;
@ -137,6 +138,7 @@ void Calibrate_MPU_Offset(IMU_Data_t *bmi088)
bmi088->GyroOffset[2] = GzOFFSET; bmi088->GyroOffset[2] = GzOFFSET;
bmi088->gNorm = gNORM; bmi088->gNorm = gNORM;
bmi088->TempWhenCali = 40; bmi088->TempWhenCali = 40;
LOGERROR("[BMI088] Calibrate Failed! Use offline params");
break; break;
} }
@ -206,7 +208,11 @@ void Calibrate_MPU_Offset(IMU_Data_t *bmi088)
gyroDiff[0] > 0.15f || gyroDiff[0] > 0.15f ||
gyroDiff[1] > 0.15f || gyroDiff[1] > 0.15f ||
gyroDiff[2] > 0.15f) gyroDiff[2] > 0.15f)
{
LOGWARNING("[bmi088] calibration was interrupted\n");
break; break;
}
DWT_Delay(0.0005); DWT_Delay(0.0005);
} }
@ -252,7 +258,10 @@ uint8_t bmi088_accel_init(void)
// check the "who am I" // check the "who am I"
if (res != BMI088_ACC_CHIP_ID_VALUE) if (res != BMI088_ACC_CHIP_ID_VALUE)
{
LOGERROR("[bmi088] Can not read bmi088 acc chip id");
return BMI088_NO_SENSOR; return BMI088_NO_SENSOR;
}
// set accel sonsor config and check // set accel sonsor config and check
for (write_reg_num = 0; write_reg_num < BMI088_WRITE_ACCEL_REG_NUM; write_reg_num++) for (write_reg_num = 0; write_reg_num < BMI088_WRITE_ACCEL_REG_NUM; write_reg_num++)
@ -294,7 +303,10 @@ uint8_t bmi088_gyro_init(void)
// check the "who am I" // check the "who am I"
if (res != BMI088_GYRO_CHIP_ID_VALUE) if (res != BMI088_GYRO_CHIP_ID_VALUE)
{
LOGERROR("[bmi088] Can not read bmi088 gyro chip id");
return BMI088_NO_SENSOR; return BMI088_NO_SENSOR;
}
// set gyro sonsor config and check // set gyro sonsor config and check
for (write_reg_num = 0; write_reg_num < BMI088_WRITE_GYRO_REG_NUM; write_reg_num++) for (write_reg_num = 0; write_reg_num < BMI088_WRITE_GYRO_REG_NUM; write_reg_num++)

View File

@ -10,11 +10,13 @@
*/ */
#include "master_process.h" #include "master_process.h"
#include "seasky_protocol.h" #include "seasky_protocol.h"
#include "daemon.h"
#include "bsp_log.h" #include "bsp_log.h"
#include "robot_def.h" #include "robot_def.h"
static Vision_Recv_s recv_data; static Vision_Recv_s recv_data;
static Vision_Send_s send_data; static Vision_Send_s send_data;
static DaemonInstance *vision_daemon_instance;
void VisionSetFlag(Enemy_Color_e enemy_color, Work_Mode_e work_mode, Bullet_Speed_e bullet_speed) void VisionSetFlag(Enemy_Color_e enemy_color, Work_Mode_e work_mode, Bullet_Speed_e bullet_speed)
{ {
@ -30,13 +32,26 @@ void VisionSetAltitude(float yaw, float pitch, float roll)
send_data.roll = roll; send_data.roll = roll;
} }
/**
* @brief 线,daemon.c中被daemon task调用
* @attention HAL库的设计问题,DMA接收之后同时发送有概率出现__HAL_LOCK(),使
* .daemon判断数据更新,.
*
* @param id vision_usart_instance的地址,.
*/
static void VisionOfflineCallback(void *id)
{
#ifdef VISION_USE_UART
USARTServiceInit(vision_usart_instance);
#endif // !VISION_USE_UART
LOGWARNING("[vision] vision offline, restart communication.");
}
#ifdef VISION_USE_UART #ifdef VISION_USE_UART
#include "bsp_usart.h" #include "bsp_usart.h"
#include "daemon.h"
static USARTInstance *vision_usart_instance; static USARTInstance *vision_usart_instance;
static DaemonInstance *vision_daemon_instance;
/** /**
* @brief ,bsp_usart.c中被usart rx callback调用 * @brief ,bsp_usart.c中被usart rx callback调用
@ -51,21 +66,8 @@ static void DecodeVision()
// TODO: code to resolve flag_register; // TODO: code to resolve flag_register;
} }
/**
* @brief 线,daemon.c中被daemon task调用
* @attention HAL库的设计问题,DMA接收之后同时发送有概率出现__HAL_LOCK(),使
* .daemon判断数据更新,.
*
* @param id vision_usart_instance的地址,.
*/
static void VisionOfflineCallback(void *id)
{
USARTServiceInit(vision_usart_instance);
}
Vision_Recv_s *VisionInit(UART_HandleTypeDef *_handle) Vision_Recv_s *VisionInit(UART_HandleTypeDef *_handle)
{ {
#ifdef VISION_USE_UART
USART_Init_Config_s conf; USART_Init_Config_s conf;
conf.module_callback = DecodeVision; conf.module_callback = DecodeVision;
conf.recv_buff_size = VISION_RECV_SIZE; conf.recv_buff_size = VISION_RECV_SIZE;
@ -79,7 +81,6 @@ Vision_Recv_s *VisionInit(UART_HandleTypeDef *_handle)
.reload_count = 10, .reload_count = 10,
}; };
vision_daemon_instance = DaemonRegister(&daemon_conf); vision_daemon_instance = DaemonRegister(&daemon_conf);
#endif // VISION_USE_UART
return &recv_data; return &recv_data;
} }
@ -125,9 +126,17 @@ static void DecodeVision(uint16_t recv_len)
Vision_Recv_s *VisionInit(UART_HandleTypeDef *_handle) Vision_Recv_s *VisionInit(UART_HandleTypeDef *_handle)
{ {
UNUSED(_handle); // 仅为了消除警告 UNUSED(_handle); // 仅为了消除警告
USB_Init_Config_s conf = {0}; USB_Init_Config_s conf = {.rx_cbk = DecodeVision};
conf.rx_cbk = DecodeVision;
vis_recv_buff = USBInit(conf); vis_recv_buff = USBInit(conf);
// 为master process注册daemon,用于判断视觉通信是否离线
Daemon_Init_Config_s daemon_conf = {
.callback = VisionOfflineCallback, // 离线时调用的回调函数,会重启串口接收
.owner_id = NULL,
.reload_count = 5, // 50ms
};
vision_daemon_instance = DaemonRegister(&daemon_conf);
return &recv_data; return &recv_data;
} }

View File

@ -4,14 +4,15 @@
#include "bsp_log.h" #include "bsp_log.h"
static uint8_t idx = 0; // register idx,是该文件的全局电机索引,在注册时使用 static uint8_t idx = 0; // register idx,是该文件的全局电机索引,在注册时使用
/* DJI电机的实例,此处仅保存指针,内存的分配将通过电机实例初始化时通过malloc()进行 */ /* DJI电机的实例,此处仅保存指针,内存的分配将通过电机实例初始化时通过malloc()进行 */
static DJIMotorInstance *dji_motor_instance[DJI_MOTOR_CNT] = {NULL}; static DJIMotorInstance *dji_motor_instance[DJI_MOTOR_CNT] = {NULL}; // 会在control任务中遍历该指针数组进行pid计算
/** /**
* @brief DJI电机发送以四个一组的形式进行,,6(2can*3group)can_instance专门负责发送 * @brief DJI电机发送以四个一组的形式进行,,6(2can*3group)can_instance专门负责发送
* DJIMotorControl() 使, MotorSenderGrouping() * DJIMotorControl() 使, MotorSenderGrouping()
* *
* @note ,bsp_can中注册
*
* C610(m2006)/C620(m3508):0x1ff,0x200; * C610(m2006)/C620(m3508):0x1ff,0x200;
* GM6020:0x1ff,0x2ff * GM6020:0x1ff,0x2ff
* (rx_id): GM6020: 0x204+id ; C610/C620: 0x200+id * (rx_id): GM6020: 0x204+id ; C610/C620: 0x200+id
@ -69,9 +70,10 @@ static void MotorSenderGrouping(DJIMotorInstance *motor, CAN_Init_Config_s *conf
{ {
if (dji_motor_instance[i]->motor_can_instance->can_handle == config->can_handle && dji_motor_instance[i]->motor_can_instance->rx_id == config->rx_id) if (dji_motor_instance[i]->motor_can_instance->can_handle == config->can_handle && dji_motor_instance[i]->motor_can_instance->rx_id == config->rx_id)
{ {
LOGERROR("[dji_motor] ID crash. Check in debug mode, add dji_motor_instance to watch to get more information."); // 后续可以把id和CAN打印出来 LOGERROR("[dji_motor] ID crash. Check in debug mode, add dji_motor_instance to watch to get more information.");
while (1) uint16_t can_bus = config->can_handle == &hcan1 ? 1 : 2;
; // 6020的id 1-4和2006/3508的id 5-8会发生冲突(若有注册,即1!5,2!6,3!7,4!8) (1!5!,LTC! (((不是) while (1) // 后续可以把id和CAN打印出来 // 6020的id 1-4和2006/3508的id 5-8会发生冲突(若有注册,即1!5,2!6,3!7,4!8) (1!5!,LTC! (((不是)
LOGERROR("[dji_motor] id [%d], can_bus [%d]", config->rx_id, can_bus);
} }
} }
break; break;
@ -98,16 +100,16 @@ static void MotorSenderGrouping(DJIMotorInstance *motor, CAN_Init_Config_s *conf
if (dji_motor_instance[i]->motor_can_instance->can_handle == config->can_handle && dji_motor_instance[i]->motor_can_instance->rx_id == config->rx_id) if (dji_motor_instance[i]->motor_can_instance->can_handle == config->can_handle && dji_motor_instance[i]->motor_can_instance->rx_id == config->rx_id)
{ {
LOGERROR("[dji_motor] ID crash. Check in debug mode, add dji_motor_instance to watch to get more information."); LOGERROR("[dji_motor] ID crash. Check in debug mode, add dji_motor_instance to watch to get more information.");
while (1) uint16_t can_bus = config->can_handle == &hcan1 ? 1 : 2;
; // 6020的id 1-4和2006/3508的id 5-8会发生冲突(若有注册,即1!5,2!6,3!7,4!8) while (1) // 后续可以把id和CAN打印出来 // 6020的id 1-4和2006/3508的id 5-8会发生冲突(若有注册,即1!5,2!6,3!7,4!8) (1!5!,LTC! (((不是)
LOGERROR("[dji_motor] id [%d], can_bus [%d]", config->rx_id, can_bus);
} }
} }
break; break;
default: // other motors should not be registered here default: // other motors should not be registered here
LOGERROR("You must not register other motors using the API of DJI motor.");
while (1) while (1)
; // 其他电机不应该在这里注册 LOGERROR("[dji_motor]You must not register other motors using the API of DJI motor."); // 其他电机不应该在这里注册
} }
} }
@ -148,6 +150,9 @@ static void DecodeDJIMotor(CANInstance *_instance)
static void DJIMotorLostCallback(void *motor_ptr) static void DJIMotorLostCallback(void *motor_ptr)
{ {
DJIMotorInstance *motor = (DJIMotorInstance *)motor_ptr;
uint16_t can_bus = motor->motor_can_instance->can_handle == &hcan1 ? 1 : 2;
LOGWARNING("[dji_motor] Motor lost, can bus [%d] , id [%d]", can_bus, motor->motor_can_instance->tx_id);
} }
// 电机初始化,返回一个电机实例 // 电机初始化,返回一个电机实例
@ -182,7 +187,7 @@ DJIMotorInstance *DJIMotorInit(Motor_Init_Config_s *config)
Daemon_Init_Config_s daemon_config = { Daemon_Init_Config_s daemon_config = {
.callback = DJIMotorLostCallback, .callback = DJIMotorLostCallback,
.owner_id = instance, .owner_id = instance,
.reload_count = 1, // 10ms未收到数据则丢失 .reload_count = 2, // 20ms未收到数据则丢失
}; };
instance->daemon = DaemonRegister(&daemon_config); instance->daemon = DaemonRegister(&daemon_config);
@ -195,17 +200,11 @@ DJIMotorInstance *DJIMotorInit(Motor_Init_Config_s *config)
void DJIMotorChangeFeed(DJIMotorInstance *motor, Closeloop_Type_e loop, Feedback_Source_e type) void DJIMotorChangeFeed(DJIMotorInstance *motor, Closeloop_Type_e loop, Feedback_Source_e type)
{ {
if (loop == ANGLE_LOOP) if (loop == ANGLE_LOOP)
{
motor->motor_settings.angle_feedback_source = type; motor->motor_settings.angle_feedback_source = type;
}
else if (loop == SPEED_LOOP) else if (loop == SPEED_LOOP)
{
motor->motor_settings.speed_feedback_source = type; motor->motor_settings.speed_feedback_source = type;
}
else else
{
LOGERROR("[dji_motor] loop type error, check memory access and func param"); // 检查是否传入了正确的LOOP类型,或发生了指针越界 LOGERROR("[dji_motor] loop type error, check memory access and func param"); // 检查是否传入了正确的LOOP类型,或发生了指针越界
}
} }
void DJIMotorStop(DJIMotorInstance *motor) void DJIMotorStop(DJIMotorInstance *motor)
@ -299,12 +298,10 @@ void DJIMotorControl()
sender_assignment[group].tx_buff[2 * num] = (uint8_t)(set >> 8); // 低八位 sender_assignment[group].tx_buff[2 * num] = (uint8_t)(set >> 8); // 低八位
sender_assignment[group].tx_buff[2 * num + 1] = (uint8_t)(set & 0x00ff); // 高八位 sender_assignment[group].tx_buff[2 * num + 1] = (uint8_t)(set & 0x00ff); // 高八位
// 电机是否停止运行 // 若该电机处于停止状态,直接将buff置零
if (motor->stop_flag == MOTOR_STOP) if (motor->stop_flag == MOTOR_STOP)
{ // 若该电机处于停止状态,直接将buff置零
memset(sender_assignment[group].tx_buff + 2 * num, 0, 16u); memset(sender_assignment[group].tx_buff + 2 * num, 0, 16u);
} }
}
// 遍历flag,检查是否要发送这一帧报文 // 遍历flag,检查是否要发送这一帧报文
for (size_t i = 0; i < 6; ++i) for (size_t i = 0; i < 6; ++i)

View File

@ -6,6 +6,7 @@
#include "string.h" #include "string.h"
#include "daemon.h" #include "daemon.h"
#include "stdlib.h" #include "stdlib.h"
#include "bsp_log.h"
static uint8_t idx; static uint8_t idx;
static HTMotorInstance *ht_motor_instance[HT_MOTOR_CNT]; static HTMotorInstance *ht_motor_instance[HT_MOTOR_CNT];
@ -64,17 +65,14 @@ static void HTMotorDecode(CANInstance *motor_can)
tmp = (uint16_t)(((rxbuff[4] & 0x0f) << 8) | rxbuff[5]); tmp = (uint16_t)(((rxbuff[4] & 0x0f) << 8) | rxbuff[5]);
measure->real_current = CURRENT_SMOOTH_COEF * uint_to_float(tmp, T_MIN, T_MAX, 12) + measure->real_current = CURRENT_SMOOTH_COEF * uint_to_float(tmp, T_MIN, T_MAX, 12) +
(1 - CURRENT_SMOOTH_COEF) * measure->real_current; (1 - CURRENT_SMOOTH_COEF) * measure->real_current;
} }
static void HTMotorLostCallback(void *motor_ptr) static void HTMotorLostCallback(void *motor_ptr)
{ {
HTMotorInstance *motor = (HTMotorInstance *)motor_ptr; HTMotorInstance *motor = (HTMotorInstance *)motor_ptr;
if (motor->stop_flag == MOTOR_STOP) LOGWARNING("[ht_motor] motor %d lost\n", motor->motor_can_instace->tx_id);
return;
if (++motor->lost_cnt % 10 != 0) if (++motor->lost_cnt % 10 != 0)
HTMotorSetMode(CMD_MOTOR_MODE, motor); // 若不在停止模式,尝试重新让电机进入控制模式 HTMotorSetMode(CMD_MOTOR_MODE, motor); // 尝试重新让电机进入控制模式
} }
/* 海泰电机一生黑,什么垃圾协议! */ /* 海泰电机一生黑,什么垃圾协议! */
@ -99,7 +97,7 @@ void HTMotorCalibEncoder(HTMotorInstance *motor)
memcpy(zero_buff, buf, 6); // 初始化的时候至少调用一次,故将其他指令为0时发送的报文保存一下,详见ht04电机说明 memcpy(zero_buff, buf, 6); // 初始化的时候至少调用一次,故将其他指令为0时发送的报文保存一下,详见ht04电机说明
CANTransmit(motor->motor_can_instace, 1); CANTransmit(motor->motor_can_instace, 1);
DWT_Delay(0.005); DWT_Delay(0.005);
HTMotorSetMode(CMD_ZERO_POSITION, motor); HTMotorSetMode(CMD_ZERO_POSITION, motor); // sb 玩意校准完了编码器也不为0
DWT_Delay(0.005); DWT_Delay(0.005);
// HTMotorSetMode(CMD_MOTOR_MODE, motor); // HTMotorSetMode(CMD_MOTOR_MODE, motor);
} }
@ -215,7 +213,7 @@ void HTMotorControlInit()
char ht_id_buff[2] = {0}; char ht_id_buff[2] = {0};
__itoa(i, ht_id_buff, 10); __itoa(i, ht_id_buff, 10);
strcat(ht_task_name, ht_id_buff); // 似乎没什么吊用,osthreaddef会把第一个变量当作宏字符串传入,作为任务名 strcat(ht_task_name, ht_id_buff); // 似乎没什么吊用,osthreaddef会把第一个变量当作宏字符串传入,作为任务名
// todo 还需要一个更优雅的方案来区分不同的电机任务 // @todo 还需要一个更优雅的方案来区分不同的电机任务
osThreadDef(ht_task_name, HTMotorTask, osPriorityNormal, 0, 128); osThreadDef(ht_task_name, HTMotorTask, osPriorityNormal, 0, 128);
ht_task_handle[i] = osThreadCreate(osThread(ht_task_name), ht_motor_instance[i]); ht_task_handle[i] = osThreadCreate(osThread(ht_task_name), ht_motor_instance[i]);
} }

View File

@ -40,3 +40,5 @@ static void HTMotorDecode(CANInstance *motor_can)
} }
} }
``` ```
第一次收到数据时默认电机处于限位处,将速度和角度都设置为零,记录当前的编码器数据,之后每次收到都减去该值.

View File

@ -3,6 +3,7 @@
#include "general_def.h" #include "general_def.h"
#include "daemon.h" #include "daemon.h"
#include "bsp_dwt.h" #include "bsp_dwt.h"
#include "bsp_log.h"
static uint8_t idx; static uint8_t idx;
static LKMotorInstance *lkmotor_instance[LK_MOTOR_MX_CNT] = {NULL}; static LKMotorInstance *lkmotor_instance[LK_MOTOR_MX_CNT] = {NULL};
@ -43,6 +44,12 @@ static void LKMotorDecode(CANInstance *_instance)
measure->total_angle = measure->total_round * 360 + measure->angle_single_round; measure->total_angle = measure->total_round * 360 + measure->angle_single_round;
} }
static void LKMotorLostCallback(void *motor_ptr)
{
LKMotorInstance *motor = (LKMotorInstance *)motor_ptr;
LOGWARNING("[LKMotor] motor lost, id: %d", motor->motor_can_ins->tx_id);
}
LKMotorInstance *LKMotorInit(Motor_Init_Config_s *config) LKMotorInstance *LKMotorInit(Motor_Init_Config_s *config)
{ {
LKMotorInstance *motor = (LKMotorInstance *)malloc(sizeof(LKMotorInstance)); LKMotorInstance *motor = (LKMotorInstance *)malloc(sizeof(LKMotorInstance));
@ -75,7 +82,7 @@ LKMotorInstance *LKMotorInit(Motor_Init_Config_s *config)
Daemon_Init_Config_s daemon_config = { Daemon_Init_Config_s daemon_config = {
.callback = NULL, .callback = NULL,
.owner_id = motor, .owner_id = motor,
.reload_count = 5, // 0.05秒 .reload_count = 5, // 50ms
}; };
motor->daemon = DaemonRegister(&daemon_config); motor->daemon = DaemonRegister(&daemon_config);

View File

@ -1,115 +0,0 @@
#include "ps_handle.h"
uint8_t PS2_RawData[9] = {0};
PS2_Instance PS2_Data = {0};
void PS2_CS(uint8_t Val)
{
if (Val)
HAL_GPIO_WritePin(PS2_CS_GPIOx, PS2_CS_Pin, GPIO_PIN_SET);
else
HAL_GPIO_WritePin(PS2_CS_GPIOx, PS2_CS_Pin, GPIO_PIN_RESET);
}
void PS2_CLK(uint8_t Val)
{
if (Val)
HAL_GPIO_WritePin(PS2_CLK_GPIOx, PS2_CLK_Pin, GPIO_PIN_SET);
else
HAL_GPIO_WritePin(PS2_CLK_GPIOx, PS2_CLK_Pin, GPIO_PIN_RESET);
}
void PS2_DO(uint8_t Val)
{
if (Val)
HAL_GPIO_WritePin(PS2_DO_GPIOx, PS2_DO_Pin, GPIO_PIN_SET);
else
HAL_GPIO_WritePin(PS2_DO_GPIOx, PS2_DO_Pin, GPIO_PIN_RESET);
}
uint8_t PS2_Read_DI()
{
return HAL_GPIO_ReadPin(PS2_DI_GPIOx, PS2_DI_Pin);
}
void PS2_Delay()
{
for (int i = 0; i < 0xBf; i++)
__NOP();
}
uint8_t PS2_ReadWrite_Byte(uint8_t TxData)
{
uint8_t TX = TxData;
uint8_t RX = 0;
for (int i = 0; i < 8; i++)
{
if (TX & 0x01)
PS2_DO(1);
else
PS2_DO(0);
TX >>= 1;
PS2_CLK(1);
PS2_Delay();
PS2_CLK(0);
RX >>= 1;
RX |= (PS2_Read_DI() << 7);
PS2_Delay();
PS2_CLK(1);
PS2_Delay();
}
return RX;
}
static void PS2_Decode()
{
if (PS2_RawData[2] == 0x5A)
{
PS2_Data.Key_Select = (~PS2_RawData[3] >> 0) & 0x01; //选择键
PS2_Data.Key_Start = (~PS2_RawData[3] >> 3) & 0x01; //开始键
//左侧按键
PS2_Data.Key_L_Up = (~PS2_RawData[3] >> 4) & 0x01;
PS2_Data.Key_L_Right = (~PS2_RawData[3] >> 5) & 0x01;
PS2_Data.Key_L_Down = (~PS2_RawData[3] >> 6) & 0x01;
PS2_Data.Key_L_Left = (~PS2_RawData[3] >> 7) & 0x01;
//后侧按键
PS2_Data.Key_L2 = (~PS2_RawData[4] >> 0) & 0x01;
PS2_Data.Key_R2 = (~PS2_RawData[4] >> 1) & 0x01;
PS2_Data.Key_L1 = (~PS2_RawData[4] >> 2) & 0x01;
PS2_Data.Key_R1 = (~PS2_RawData[4] >> 3) & 0x01;
//右侧按键
PS2_Data.Key_R_Up = (~PS2_RawData[4] >> 4) & 0x01;
PS2_Data.Key_R_Right = (~PS2_RawData[4] >> 5) & 0x01;
PS2_Data.Key_R_Down = (~PS2_RawData[4] >> 6) & 0x01;
PS2_Data.Key_R_Left = (~PS2_RawData[4] >> 7) & 0x01;
if (PS2_RawData[1] == 0x41)
{ //无灯模式(摇杆值八向)
PS2_Data.Rocker_LX = 127 * (PS2_Data.Key_L_Right - PS2_Data.Key_L_Left);
PS2_Data.Rocker_LY = 127 * (PS2_Data.Key_L_Up - PS2_Data.Key_L_Down);
PS2_Data.Rocker_RX = 127 * (PS2_Data.Key_R_Right - PS2_Data.Key_R_Left);
PS2_Data.Rocker_RY = 127 * (PS2_Data.Key_R_Up - PS2_Data.Key_R_Down);
}
else if (PS2_RawData[1] == 0x73)
{ //红灯模式(摇杆值模拟)
//摇杆按键
PS2_Data.Key_Rocker_Left = (~PS2_RawData[3] >> 1) & 0x01;
PS2_Data.Key_Rocker_Right = (~PS2_RawData[3] >> 2) & 0x01;
//摇杆值
PS2_Data.Rocker_LX = PS2_RawData[7] - 0x80;
PS2_Data.Rocker_LY = -1 - (PS2_RawData[8] - 0x80);
PS2_Data.Rocker_RX = PS2_RawData[5] - 0x80;
PS2_Data.Rocker_RY = -1 - (PS2_RawData[6] - 0x80);
}
}
}
void PS2_Read_Data(void)
{
PS2_CS(0);
PS2_RawData[0] = PS2_ReadWrite_Byte(0x01); // 0
PS2_RawData[1] = PS2_ReadWrite_Byte(0x42); // 1
for (int i = 2; i < 9; i++)
PS2_RawData[i] = PS2_ReadWrite_Byte(0xff);
PS2_CS(1);
PS2_Decode();
}

View File

@ -1,38 +0,0 @@
#ifndef PS_HANDLE_H
#define PS_HANDLE_H
#include "bsp_spi.h"
#include "bsp_gpio.h"
#include "bsp_dwt.h"
#define PS2_CS_GPIOx GPIOB
#define PS2_CS_Pin GPIO_PIN_12
#define PS2_CLK_GPIOx GPIOB
#define PS2_CLK_Pin GPIO_PIN_13
#define PS2_DO_GPIOx GPIOB
#define PS2_DO_Pin GPIO_PIN_15
#define PS2_DI_GPIOx GPIOB
#define PS2_DI_Pin GPIO_PIN_14
typedef struct
{
uint8_t A_D; //模拟(红灯)为1 数字(无灯)为0
int8_t Rocker_RX, Rocker_RY, Rocker_LX, Rocker_LY; //摇杆值(模拟状态为实际值0-0xFF)(数字态为等效的值0,0x80,0xFF)
//按键值0为未触发,1为触发态
uint8_t Key_L1, Key_L2, Key_R1, Key_R2; //后侧大按键
uint8_t Key_L_Right, Key_L_Left, Key_L_Up, Key_L_Down; //左侧按键
uint8_t Key_R_Right, Key_R_Left, Key_R_Up, Key_R_Down; //右侧按键
uint8_t Key_Select; //选择键
uint8_t Key_Start; //开始键
uint8_t Key_Rocker_Left, Key_Rocker_Right; //摇杆按键
} PS2_Instance;
#endif // !PS_HANDLE_H#define PS_HANDLE_H

View File

@ -1,3 +0,0 @@
# ps_handle
提供ps手柄的支持,其通信协议和spi类似,可以使用bsp_spi来兼容.待编写.

View File

@ -15,8 +15,9 @@
#include "bsp_usart.h" #include "bsp_usart.h"
#include "task.h" #include "task.h"
#include "daemon.h" #include "daemon.h"
#include "bsp_log.h"
#define RE_RX_BUFFER_SIZE 200 #define RE_RX_BUFFER_SIZE 255u // 裁判系统接收缓冲区大小
static USARTInstance *referee_usart_instance; // 裁判系统串口实例 static USARTInstance *referee_usart_instance; // 裁判系统串口实例
static DaemonInstance *referee_daemon; // 裁判系统守护进程 static DaemonInstance *referee_daemon; // 裁判系统守护进程
@ -114,6 +115,7 @@ static void RefereeRxCallback()
static void RefereeLostCallback(void *arg) static void RefereeLostCallback(void *arg)
{ {
USARTServiceInit(referee_usart_instance); USARTServiceInit(referee_usart_instance);
LOGWARNING("[rm_ref] lost referee data");
} }
/* 裁判系统通信初始化 */ /* 裁判系统通信初始化 */
@ -122,7 +124,7 @@ referee_info_t *RefereeInit(UART_HandleTypeDef *referee_usart_handle)
USART_Init_Config_s conf; USART_Init_Config_s conf;
conf.module_callback = RefereeRxCallback; conf.module_callback = RefereeRxCallback;
conf.usart_handle = referee_usart_handle; conf.usart_handle = referee_usart_handle;
conf.recv_buff_size = RE_RX_BUFFER_SIZE; conf.recv_buff_size = RE_RX_BUFFER_SIZE; // mx 255(u8)
referee_usart_instance = USARTRegister(&conf); referee_usart_instance = USARTRegister(&conf);
Daemon_Init_Config_s daemon_conf = { Daemon_Init_Config_s daemon_conf = {
@ -143,5 +145,5 @@ void RefereeSend(uint8_t *send, uint16_t tx_len)
{ {
static TickType_t xLastWakeTime; static TickType_t xLastWakeTime;
USARTSend(referee_usart_instance, send, tx_len, USART_TRANSFER_DMA); USARTSend(referee_usart_instance, send, tx_len, USART_TRANSFER_DMA);
vTaskDelayUntil(&xLastWakeTime, 120); vTaskDelayUntil(&xLastWakeTime, 120); // 裁判系统接收ui数据和多机通信最大支持频率为10Hz
} }

View File

@ -4,6 +4,7 @@
#include "memory.h" #include "memory.h"
#include "stdlib.h" #include "stdlib.h"
#include "daemon.h" #include "daemon.h"
#include "bsp_log.h"
#define REMOTE_CONTROL_FRAME_SIZE 18u // 遥控器接收的buffer大小 #define REMOTE_CONTROL_FRAME_SIZE 18u // 遥控器接收的buffer大小
@ -104,6 +105,7 @@ static void RCLostCallback(void *id)
{ {
memset(rc_ctrl, 0, sizeof(rc_ctrl)); // 清空遥控器数据 memset(rc_ctrl, 0, sizeof(rc_ctrl)); // 清空遥控器数据
USARTServiceInit(rc_usart_instance); // 尝试重新启动接收 USARTServiceInit(rc_usart_instance); // 尝试重新启动接收
LOGWARNING("[rc] remote control lost");
} }
RC_ctrl_t *RemoteControlInit(UART_HandleTypeDef *rc_usart_handle) RC_ctrl_t *RemoteControlInit(UART_HandleTypeDef *rc_usart_handle)