Merge branch 'master' of https://gitee.com/hnuyuelurm/basic_framework
This commit is contained in:
commit
2404edd4eb
|
@ -69,6 +69,7 @@
|
|||
#define configUSE_16_BIT_TICKS 0
|
||||
#define configUSE_MUTEXES 1
|
||||
#define configQUEUE_REGISTRY_SIZE 8
|
||||
#define configUSE_COUNTING_SEMAPHORES 1
|
||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||
/* USER CODE BEGIN MESSAGE_BUFFER_LENGTH_TYPE */
|
||||
/* Defaults to size_t for backward compatibility, but can be changed
|
||||
|
|
|
@ -52,6 +52,7 @@ void MemManage_Handler(void);
|
|||
void BusFault_Handler(void);
|
||||
void UsageFault_Handler(void);
|
||||
void DebugMon_Handler(void);
|
||||
void FLASH_IRQHandler(void);
|
||||
void EXTI3_IRQHandler(void);
|
||||
void EXTI4_IRQHandler(void);
|
||||
void DMA1_Stream1_IRQHandler(void);
|
||||
|
|
16
Makefile
16
Makefile
|
@ -119,6 +119,7 @@ bsp/can/bsp_can.c \
|
|||
bsp/usart/bsp_usart.c \
|
||||
bsp/usb/bsp_usb.c \
|
||||
bsp/log/bsp_log.c \
|
||||
bsp/flash/bsp_flash.c \
|
||||
bsp/bsp_init.c \
|
||||
modules/algorithm/controller.c \
|
||||
modules/algorithm/kalman_filter.c \
|
||||
|
@ -152,6 +153,7 @@ modules/can_comm/can_comm.c \
|
|||
modules/message_center/message_center.c \
|
||||
modules/daemon/daemon.c \
|
||||
modules/vofa/vofa.c \
|
||||
modules/alarm/buzzer.c \
|
||||
application/gimbal/gimbal.c \
|
||||
application/chassis/chassis.c \
|
||||
application/shoot/shoot.c \
|
||||
|
@ -197,7 +199,7 @@ FPU = -mfpu=fpv4-sp-d16
|
|||
FLOAT-ABI = -mfloat-abi=hard
|
||||
|
||||
# mcu
|
||||
MCU = $(CPU) -mthumb $(FPU) $(FLOAT-ABI)
|
||||
MCU = $(CPU) -mthumb -mthumb-interwork $(FPU) $(FLOAT-ABI)
|
||||
|
||||
# macros for gcc
|
||||
# AS defines
|
||||
|
@ -209,7 +211,9 @@ C_DEFS = \
|
|||
-DSTM32F407xx \
|
||||
-DARM_MATH_CM4 \
|
||||
-DARM_MATH_MATRIX_CHECK \
|
||||
-DARM_MATH_ROUNDING
|
||||
-DARM_MATH_ROUNDING \
|
||||
-DARM_MATH_LOOPUNROLL \
|
||||
-DISABLEFLOAT16
|
||||
|
||||
# AS includes
|
||||
AS_INCLUDES = \
|
||||
|
@ -244,6 +248,7 @@ C_INCLUDES = \
|
|||
-Ibsp/spi \
|
||||
-Ibsp/iic \
|
||||
-Ibsp/log \
|
||||
-Ibsp/flash \
|
||||
-Ibsp/pwm \
|
||||
-Ibsp/bsp_legacy_support \
|
||||
-Ibsp \
|
||||
|
@ -268,13 +273,14 @@ C_INCLUDES = \
|
|||
-Imodules/message_center \
|
||||
-Imodules/daemon \
|
||||
-Imodules/vofa \
|
||||
-Imodules/alarm \
|
||||
-Imodules
|
||||
|
||||
|
||||
# compile gcc flags
|
||||
ASFLAGS = $(MCU) $(AS_DEFS) $(AS_INCLUDES) $(OPT) -fdata-sections -ffunction-sections
|
||||
|
||||
CFLAGS += $(MCU) $(C_DEFS) $(C_INCLUDES) $(OPT) -fdata-sections -ffunction-sections
|
||||
CFLAGS += $(MCU) $(C_DEFS) $(C_INCLUDES) $(OPT) -fdata-sections -ffunction-sections -fmessage-length=0
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
CFLAGS += -g -gdwarf-2
|
||||
|
@ -296,7 +302,7 @@ LIBS = -lc -lm -lnosys \
|
|||
-l:libCMSISDSP.a
|
||||
LIBDIR = \
|
||||
-LMiddlewares/ST/ARM/DSP/Lib
|
||||
LDFLAGS = $(MCU) -specs=nano.specs -T$(LDSCRIPT) $(LIBDIR) $(LIBS) -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref -Wl,--gc-sections
|
||||
LDFLAGS = $(MCU) -specs=nano.specs -T$(LDSCRIPT) $(LIBDIR) $(LIBS) -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref -Wl,--gc-sections -flto
|
||||
|
||||
# default action: build all
|
||||
all: $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin
|
||||
|
@ -336,7 +342,7 @@ $(BUILD_DIR):
|
|||
# clean up
|
||||
#######################################
|
||||
clean:
|
||||
rd /s/q $(BUILD_DIR)
|
||||
rd $(BUILD_DIR) /s/q
|
||||
|
||||
|
||||
#######################################
|
||||
|
|
|
@ -123,9 +123,9 @@ void MX_FREERTOS_Init(void)
|
|||
void StartDefaultTask(void const *argument)
|
||||
{
|
||||
/* init code for USB_DEVICE */
|
||||
MX_USB_DEVICE_Init(); // USB???
|
||||
MX_USB_DEVICE_Init(); // 默认usb启动任务的位置
|
||||
/* USER CODE BEGIN StartDefaultTask */
|
||||
vTaskDelete(NULL); // ??????,????CPU
|
||||
vTaskDelete(NULL); // 避免空置和切换占用cpu
|
||||
/* USER CODE END StartDefaultTask */
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
/* Private includes ----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Includes */
|
||||
#include "robot.h"
|
||||
#include "bsp_log.h"
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
|
@ -120,6 +121,7 @@ int main(void)
|
|||
MX_DAC_Init();
|
||||
/* USER CODE BEGIN 2 */
|
||||
RobotInit(); // 唯一的初始化函数
|
||||
LOGINFO("[main] SystemInit() and RobotInit() done");
|
||||
/* USER CODE END 2 */
|
||||
|
||||
/* Call init function for freertos objects (in freertos.c) */
|
||||
|
|
|
@ -73,6 +73,11 @@ void HAL_MspInit(void)
|
|||
/* PendSV_IRQn interrupt configuration */
|
||||
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 END MspInit 1 */
|
||||
|
|
|
@ -183,6 +183,20 @@ void DebugMon_Handler(void)
|
|||
/* 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.
|
||||
*/
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#include "usbd_cdc.h"
|
||||
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
#include "bsp_dwt.h"
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
|
@ -95,7 +95,11 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef* pcdHandle)
|
|||
HAL_NVIC_SetPriority(OTG_FS_IRQn, 5, 0);
|
||||
HAL_NVIC_EnableIRQ(OTG_FS_IRQn);
|
||||
/* 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 */
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
#include "message_center.h"
|
||||
#include "general_def.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
|
||||
|
@ -129,16 +132,8 @@ static void RemoteControlSet()
|
|||
{ // 按照摇杆的输出大小进行角度增量,增益系数需调整
|
||||
gimbal_cmd_send.yaw += 0.005f * (float)rc_data[TEMP].rc.rocker_l_;
|
||||
gimbal_cmd_send.pitch += 0.001f * (float)rc_data[TEMP].rc.rocker_l1;
|
||||
// 摇杆控制的软件限位
|
||||
// if (gimbal_cmd_send.pitch <= PITCH_MIN_ECD)
|
||||
// {
|
||||
// gimbal_cmd_send.pitch = PITCH_MIN_ECD;
|
||||
// }
|
||||
// else if (gimbal_cmd_send.pitch >= PITCH_MAX_ECD)
|
||||
// {
|
||||
// gimbal_cmd_send.pitch = PITCH_MAX_ECD;
|
||||
// }
|
||||
}
|
||||
// 云台软件限位
|
||||
|
||||
// 底盘参数,目前没有加入小陀螺(调试似乎暂时没有必要),系数需要调整
|
||||
chassis_cmd_send.vx = 10.0f * (float)rc_data[TEMP].rc.rocker_r_; // _水平方向
|
||||
|
@ -266,12 +261,14 @@ static void EmergencyHandler()
|
|||
shoot_cmd_send.shoot_mode = SHOOT_OFF;
|
||||
shoot_cmd_send.friction_mode = FRICTION_OFF;
|
||||
shoot_cmd_send.load_mode = LOAD_STOP;
|
||||
LOGERROR("[CMD] emergency stop!");
|
||||
}
|
||||
// 遥控器右侧开关为[上],恢复正常运行
|
||||
if (switch_is_up(rc_data[TEMP].rc.switch_right))
|
||||
{
|
||||
robot_state = ROBOT_READY;
|
||||
shoot_cmd_send.shoot_mode = SHOOT_ON;
|
||||
LOGINFO("[CMD] reinstate, robot ready");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
#include "daemon.h"
|
||||
#include "HT04.h"
|
||||
|
||||
#include "bsp_log.h"
|
||||
|
||||
osThreadId insTaskHandle;
|
||||
osThreadId robotTaskHandle;
|
||||
osThreadId motorTaskHandle;
|
||||
|
@ -54,12 +56,15 @@ void StartINSTASK(void const *argument)
|
|||
{
|
||||
static float ins_start, ins_dt;
|
||||
INS_Init(); // 确保BMI088被正确初始化.
|
||||
LOGINFO("[freeRTOS] INS Task Start");
|
||||
while (1)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
|
@ -68,21 +73,30 @@ void StartINSTASK(void const *argument)
|
|||
void StartMOTORTASK(void const *argument)
|
||||
{
|
||||
static float motor_dt, motor_start;
|
||||
LOGINFO("[freeRTOS] MOTOR Task Start");
|
||||
while (1)
|
||||
{
|
||||
motor_start = DWT_GetTimeline_ms();
|
||||
MotorControlTask();
|
||||
motor_dt = DWT_GetTimeline_ms() - motor_start;
|
||||
if (motor_dt > 1)
|
||||
LOGERROR("[freeRTOS] MOTOR Task is being DELAY! dt = [%f]", &motor_dt);
|
||||
osDelay(1);
|
||||
}
|
||||
}
|
||||
|
||||
void StartDAEMONTASK(void const *argument)
|
||||
{
|
||||
static float daemon_dt, daemon_start;
|
||||
LOGINFO("[freeRTOS] Daemon Task Start");
|
||||
while (1)
|
||||
{
|
||||
// 100Hz
|
||||
daemon_start = DWT_GetTimeline_ms();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -90,19 +104,24 @@ void StartDAEMONTASK(void const *argument)
|
|||
void StartROBOTTASK(void const *argument)
|
||||
{
|
||||
static float robot_dt, robot_start;
|
||||
LOGINFO("[freeRTOS] ROBOT core Task Start");
|
||||
// 200Hz-500Hz,若有额外的控制任务如平衡步兵可能需要提升至1kHz
|
||||
while (1)
|
||||
{
|
||||
robot_start = DWT_GetTimeline_ms();
|
||||
RobotTask();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void StartUITASK(void const *argument)
|
||||
{
|
||||
LOGINFO("[freeRTOS] UI Task Start");
|
||||
MyUIInit();
|
||||
LOGINFO("[freeRTOS] UI Init Done, communication with ref has established");
|
||||
while (1)
|
||||
{
|
||||
// 每给裁判系统发送一包数据会挂起一次,详见UITask函数的refereeSend()
|
||||
|
|
|
@ -174,11 +174,12 @@ Dma.USART6_TX.1.PeriphInc=DMA_PINC_DISABLE
|
|||
Dma.USART6_TX.1.Priority=DMA_PRIORITY_HIGH
|
||||
Dma.USART6_TX.1.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode,FIFOThreshold,MemBurst,PeriphBurst
|
||||
FREERTOS.INCLUDE_vTaskDelayUntil=1
|
||||
FREERTOS.IPParameters=Tasks01,configENABLE_FPU,configMAX_TASK_NAME_LEN,configUSE_TIMERS,configUSE_POSIX_ERRNO,INCLUDE_vTaskDelayUntil,configTOTAL_HEAP_SIZE
|
||||
FREERTOS.IPParameters=Tasks01,configENABLE_FPU,configMAX_TASK_NAME_LEN,configUSE_TIMERS,configUSE_POSIX_ERRNO,INCLUDE_vTaskDelayUntil,configTOTAL_HEAP_SIZE,configUSE_COUNTING_SEMAPHORES
|
||||
FREERTOS.Tasks01=defaultTask,0,128,StartDefaultTask,Default,NULL,Dynamic,NULL,NULL
|
||||
FREERTOS.configENABLE_FPU=1
|
||||
FREERTOS.configMAX_TASK_NAME_LEN=32
|
||||
FREERTOS.configTOTAL_HEAP_SIZE=20000
|
||||
FREERTOS.configUSE_COUNTING_SEMAPHORES=1
|
||||
FREERTOS.configUSE_POSIX_ERRNO=0
|
||||
FREERTOS.configUSE_TIMERS=0
|
||||
File.Version=6
|
||||
|
@ -308,6 +309,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.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.FLASH_IRQn=true\:6\:0\:true\:false\:true\:true\:true\:true\:true
|
||||
NVIC.ForceEnableDMAVector=true
|
||||
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
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#include "bsp_log.h"
|
||||
#include "bsp_dwt.h"
|
||||
#include "bsp_usb.h"
|
||||
#include "bsp_buzzer.h"
|
||||
#include "buzzer.h"
|
||||
#include "bsp_led.h"
|
||||
#include "bsp_temperature.h"
|
||||
|
||||
|
@ -15,5 +15,5 @@ void BSPInit()
|
|||
// legacy support,待删除,将在实现了led/tempctrl/buzzer的module之后移动到app层进行XXXRegister()
|
||||
LEDInit();
|
||||
IMUTempInit();
|
||||
BuzzerInit();
|
||||
buzzer_init();
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
#include "bsp_buzzer.h"
|
||||
#include "main.h"
|
||||
|
||||
#warning this is a legacy support file, please use the new version
|
||||
|
||||
extern TIM_HandleTypeDef htim4;
|
||||
static uint8_t tmp_warning_level = 0;
|
||||
|
||||
void BuzzerInit()
|
||||
{
|
||||
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_3);
|
||||
}
|
||||
|
||||
void BuzzerOn(uint16_t psc, uint16_t pwm, uint8_t level)
|
||||
{
|
||||
if (level > tmp_warning_level)
|
||||
{
|
||||
tmp_warning_level = level;
|
||||
__HAL_TIM_PRESCALER(&htim4, psc);
|
||||
__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, pwm);
|
||||
}
|
||||
}
|
||||
|
||||
void BuzzerOff(void)
|
||||
{
|
||||
__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, 0);
|
||||
tmp_warning_level = 0;
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
#ifndef BSP_BUZZER_H
|
||||
#define BSP_BUZZER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void BuzzerInit();
|
||||
extern void BuzzerOn(uint16_t psc, uint16_t pwm, uint8_t level);
|
||||
extern void BuzzerOff(void);
|
||||
|
||||
#endif
|
|
@ -65,15 +65,20 @@ CANInstance *CANRegister(CAN_Init_Config_s *config)
|
|||
if (!idx)
|
||||
{
|
||||
CANServiceInit(); // 第一次注册,先进行硬件初始化
|
||||
LOGINFO("[bsp_can] CAN Service Init");
|
||||
}
|
||||
if (idx >= CAN_MX_REGISTER_CNT) // 超过最大实例数
|
||||
{
|
||||
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++)
|
||||
{ // 重复注册 | id重复
|
||||
if (can_instance[i]->rx_id == config->rx_id && can_instance[i]->can_handle == config->can_handle)
|
||||
{
|
||||
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)); // 分配空间
|
||||
|
@ -107,7 +112,7 @@ uint8_t CANTransmit(CANInstance *_instance, float 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++;
|
||||
return 0;
|
||||
}
|
||||
|
@ -116,7 +121,7 @@ uint8_t CANTransmit(CANInstance *_instance, float timeout)
|
|||
// 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++;
|
||||
return 0;
|
||||
}
|
||||
|
@ -125,9 +130,10 @@ uint8_t CANTransmit(CANInstance *_instance, float timeout)
|
|||
|
||||
void CANSetDLC(CANInstance *_instance, uint8_t length)
|
||||
{
|
||||
// 发送长度错误!检查调用参数是否出错,或出现野指针/越界访问
|
||||
if (length > 8 || length == 0) // 安全检查
|
||||
while (1)
|
||||
; // 发送长度错误!检查调用参数是否出错,或出现野指针/越界访问
|
||||
LOGERROR("[bsp_can] CAN DLC error! check your code or wild pointer");
|
||||
_instance->txconf.DLC = length;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,8 +21,8 @@ static osMutexId DWT_MUTEX;
|
|||
/**
|
||||
* @brief 私有函数,用于检查DWT CYCCNT寄存器是否溢出,并更新CYCCNT_RountCount
|
||||
* @attention 此函数假设两次调用之间的时间间隔不超过一次溢出
|
||||
*
|
||||
* @todo 更好的方案是为dwt的时间更新单独设置一个任务
|
||||
*
|
||||
* @todo 更好的方案是为dwt的时间更新单独设置一个任务?
|
||||
* 不过,使用dwt的初衷是定时不被中断/任务等因素影响,因此该实现仍然有其存在的意义
|
||||
*
|
||||
*/
|
||||
|
@ -31,7 +31,7 @@ static void DWT_CNT_Update(void)
|
|||
if (__get_CONTROL()) // 不在中断中,使用互斥锁;在中断则直接执行即可,本框架将所有中断优先级设置为相同,故不会被其他中断重入
|
||||
if (osOK != osMutexWait(DWT_MUTEX, 0))
|
||||
return;
|
||||
|
||||
|
||||
volatile uint32_t cnt_now = DWT->CYCCNT;
|
||||
if (cnt_now < CYCCNT_LAST)
|
||||
CYCCNT_RountCount++;
|
||||
|
@ -131,6 +131,5 @@ void DWT_Delay(float Delay)
|
|||
float wait = Delay;
|
||||
|
||||
while ((DWT->CYCCNT - tickstart) < wait * (float)CPU_FREQ_Hz)
|
||||
{
|
||||
}
|
||||
;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
******************************************************************************
|
||||
* @file bsp_dwt.h
|
||||
* @author Wang Hongxi
|
||||
* @version V1.1.0
|
||||
* @author modified by NeoZng
|
||||
* @version V1.2.0
|
||||
* @date 2022/3/8
|
||||
* @brief
|
||||
******************************************************************************
|
||||
|
@ -15,6 +16,7 @@
|
|||
|
||||
#include "main.h"
|
||||
#include "stdint.h"
|
||||
#include "bsp_log.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
@ -23,17 +25,30 @@ typedef struct
|
|||
uint16_t us;
|
||||
} 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
|
||||
*
|
||||
*
|
||||
* @param CPU_Freq_mHz c板为168MHz,A板为180MHz
|
||||
*/
|
||||
void DWT_Init(uint32_t CPU_Freq_mHz);
|
||||
|
||||
/**
|
||||
* @brief 获取两次调用之间的时间间隔,单位为秒/s
|
||||
*
|
||||
*
|
||||
* @param cnt_last 上一次调用的时间戳
|
||||
* @return float 时间间隔,单位为秒/s
|
||||
*/
|
||||
|
@ -41,7 +56,7 @@ float DWT_GetDeltaT(uint32_t *cnt_last);
|
|||
|
||||
/**
|
||||
* @brief 获取两次调用之间的时间间隔,单位为秒/s,高精度
|
||||
*
|
||||
*
|
||||
* @param cnt_last 上一次调用的时间戳
|
||||
* @return double 时间间隔,单位为秒/s
|
||||
*/
|
||||
|
@ -49,22 +64,22 @@ double DWT_GetDeltaT64(uint32_t *cnt_last);
|
|||
|
||||
/**
|
||||
* @brief 获取当前时间,单位为秒/s,即初始化后的时间
|
||||
*
|
||||
*
|
||||
* @return float 时间轴
|
||||
*/
|
||||
float DWT_GetTimeline_s(void);
|
||||
|
||||
/**
|
||||
* @brief 获取当前时间,单位为毫秒/ms,即初始化后的时间
|
||||
*
|
||||
* @return float
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
float DWT_GetTimeline_ms(void);
|
||||
|
||||
/**
|
||||
* @brief 获取当前时间,单位为微秒/us,即初始化后的时间
|
||||
*
|
||||
* @return uint64_t
|
||||
*
|
||||
* @return uint64_t
|
||||
*/
|
||||
uint64_t DWT_GetTimeline_us(void);
|
||||
|
||||
|
@ -72,7 +87,7 @@ uint64_t DWT_GetTimeline_us(void);
|
|||
* @brief DWT延时函数,单位为秒/s
|
||||
* @attention 该函数不受中断是否开启的影响,可以在临界区和关闭中断时使用
|
||||
* @note 禁止在__disable_irq()和__enable_irq()之间使用HAL_Delay()函数,应使用本函数
|
||||
*
|
||||
*
|
||||
* @param Delay 延时时间,单位为秒/s
|
||||
*/
|
||||
void DWT_Delay(float Delay);
|
||||
|
@ -83,6 +98,4 @@ void DWT_Delay(float Delay);
|
|||
*/
|
||||
void DWT_SysTimeUpdate(void);
|
||||
|
||||
|
||||
|
||||
#endif /* BSP_DWT_H_ */
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
DWT是stm32内部的一个"隐藏资源",他的用途是给下载器提供准确的定时,从而为调试信息加上时间戳.并在固定的时间间隔将调试数据发送到你的xxlink上.
|
||||
|
||||
|
||||
|
||||
## 常用功能
|
||||
|
||||
### 计算两次进入同一个函数的时间间隔
|
||||
|
@ -23,8 +21,34 @@ start=DWT_DetTimeline_ms();
|
|||
|
||||
// some proc to go...
|
||||
for(uint8_t i=0;i<10;i++)
|
||||
foo();
|
||||
foo();
|
||||
|
||||
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;
|
||||
```
|
||||
|
|
|
@ -0,0 +1,289 @@
|
|||
#include "bsp_flash.h"
|
||||
#include "main.h"
|
||||
#include "string.h"
|
||||
|
||||
static uint32_t ger_sector(uint32_t address);
|
||||
|
||||
/**
|
||||
* @brief erase flash
|
||||
* @param[in] address: flash address
|
||||
* @param[in] len: page num
|
||||
* @retval none
|
||||
*/
|
||||
/**
|
||||
* @brief 擦除flash
|
||||
* @param[in] address: flash 地址
|
||||
* @param[in] len: 页数量
|
||||
* @retval none
|
||||
*/
|
||||
void flash_erase_address(uint32_t address, uint16_t len)
|
||||
{
|
||||
FLASH_EraseInitTypeDef flash_erase;
|
||||
uint32_t error;
|
||||
|
||||
flash_erase.Sector = ger_sector(address);
|
||||
flash_erase.TypeErase = FLASH_TYPEERASE_SECTORS;
|
||||
flash_erase.VoltageRange = FLASH_VOLTAGE_RANGE_3;
|
||||
flash_erase.NbSectors = len;
|
||||
|
||||
HAL_FLASH_Unlock();
|
||||
HAL_FLASHEx_Erase(&flash_erase, &error);
|
||||
HAL_FLASH_Lock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief write data to one page of flash
|
||||
* @param[in] start_address: flash address
|
||||
* @param[in] buf: data point
|
||||
* @param[in] len: data num
|
||||
* @retval success 0, fail -1
|
||||
*/
|
||||
/**
|
||||
* @brief 往一页flash写数据
|
||||
* @param[in] start_address: flash 地址
|
||||
* @param[in] buf: 数据指针
|
||||
* @param[in] len: 数据长度
|
||||
* @retval success 0, fail -1
|
||||
*/
|
||||
int8_t flash_write_single_address(uint32_t start_address, uint32_t *buf, uint32_t len)
|
||||
{
|
||||
static uint32_t uw_address;
|
||||
static uint32_t end_address;
|
||||
static uint32_t *data_buf;
|
||||
static uint32_t data_len;
|
||||
|
||||
HAL_FLASH_Unlock();
|
||||
|
||||
uw_address = start_address;
|
||||
end_address = get_next_flash_address(start_address);
|
||||
data_buf = buf;
|
||||
data_len = 0;
|
||||
|
||||
while (uw_address <= end_address)
|
||||
{
|
||||
|
||||
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,uw_address, *data_buf) == HAL_OK)
|
||||
{
|
||||
uw_address += 4;
|
||||
data_buf++;
|
||||
data_len++;
|
||||
if (data_len == len)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HAL_FLASH_Lock();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
HAL_FLASH_Lock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief write data to some pages of flash
|
||||
* @param[in] start_address: flash start address
|
||||
* @param[in] end_address: flash end address
|
||||
* @param[in] buf: data point
|
||||
* @param[in] len: data num
|
||||
* @retval success 0, fail -1
|
||||
*/
|
||||
/**
|
||||
* @brief 往几页flash写数据
|
||||
* @param[in] start_address: flash 开始地址
|
||||
* @param[in] end_address: flash 结束地址
|
||||
* @param[in] buf: 数据指针
|
||||
* @param[in] len: 数据长度
|
||||
* @retval success 0, fail -1
|
||||
*/
|
||||
int8_t flash_write_muli_address(uint32_t start_address, uint32_t end_address, uint32_t *buf, uint32_t len)
|
||||
{
|
||||
uint32_t uw_address = 0;
|
||||
uint32_t *data_buf;
|
||||
uint32_t data_len;
|
||||
|
||||
HAL_FLASH_Unlock();
|
||||
|
||||
uw_address = start_address;
|
||||
data_buf = buf;
|
||||
data_len = 0;
|
||||
while (uw_address <= end_address)
|
||||
{
|
||||
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,uw_address, *data_buf) == HAL_OK)
|
||||
{
|
||||
uw_address += 4;
|
||||
data_buf++;
|
||||
data_len++;
|
||||
if (data_len == len)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HAL_FLASH_Lock();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
HAL_FLASH_Lock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief read data for flash
|
||||
* @param[in] address: flash address
|
||||
* @param[out] buf: data point
|
||||
* @param[in] len: data num
|
||||
* @retval none
|
||||
*/
|
||||
/**
|
||||
* @brief 从flash读数据
|
||||
* @param[in] start_address: flash 地址
|
||||
* @param[out] buf: 数据指针
|
||||
* @param[in] len: 数据长度
|
||||
* @retval none
|
||||
*/
|
||||
void flash_read(uint32_t address, uint32_t *buf, uint32_t len)
|
||||
{
|
||||
memcpy(buf, (void*)address, len *4);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief get the sector number of flash
|
||||
* @param[in] address: flash address
|
||||
* @retval sector number
|
||||
*/
|
||||
/**
|
||||
* @brief 获取flash的sector号
|
||||
* @param[in] address: flash 地址
|
||||
* @retval sector号
|
||||
*/
|
||||
static uint32_t ger_sector(uint32_t address)
|
||||
{
|
||||
uint32_t sector = 0;
|
||||
if ((address < ADDR_FLASH_SECTOR_1) && (address >= ADDR_FLASH_SECTOR_0))
|
||||
{
|
||||
sector = FLASH_SECTOR_0;
|
||||
}
|
||||
else if ((address < ADDR_FLASH_SECTOR_2) && (address >= ADDR_FLASH_SECTOR_1))
|
||||
{
|
||||
sector = FLASH_SECTOR_1;
|
||||
}
|
||||
else if ((address < ADDR_FLASH_SECTOR_3) && (address >= ADDR_FLASH_SECTOR_2))
|
||||
{
|
||||
sector = FLASH_SECTOR_2;
|
||||
}
|
||||
else if ((address < ADDR_FLASH_SECTOR_4) && (address >= ADDR_FLASH_SECTOR_3))
|
||||
{
|
||||
sector = FLASH_SECTOR_3;
|
||||
}
|
||||
else if ((address < ADDR_FLASH_SECTOR_5) && (address >= ADDR_FLASH_SECTOR_4))
|
||||
{
|
||||
sector = FLASH_SECTOR_4;
|
||||
}
|
||||
else if ((address < ADDR_FLASH_SECTOR_6) && (address >= ADDR_FLASH_SECTOR_5))
|
||||
{
|
||||
sector = FLASH_SECTOR_5;
|
||||
}
|
||||
else if ((address < ADDR_FLASH_SECTOR_7) && (address >= ADDR_FLASH_SECTOR_6))
|
||||
{
|
||||
sector = FLASH_SECTOR_6;
|
||||
}
|
||||
else if ((address < ADDR_FLASH_SECTOR_8) && (address >= ADDR_FLASH_SECTOR_7))
|
||||
{
|
||||
sector = FLASH_SECTOR_7;
|
||||
}
|
||||
else if ((address < ADDR_FLASH_SECTOR_9) && (address >= ADDR_FLASH_SECTOR_8))
|
||||
{
|
||||
sector = FLASH_SECTOR_8;
|
||||
}
|
||||
else if ((address < ADDR_FLASH_SECTOR_10) && (address >= ADDR_FLASH_SECTOR_9))
|
||||
{
|
||||
sector = FLASH_SECTOR_9;
|
||||
}
|
||||
else if ((address < ADDR_FLASH_SECTOR_11) && (address >= ADDR_FLASH_SECTOR_10))
|
||||
{
|
||||
sector = FLASH_SECTOR_10;
|
||||
}
|
||||
else if ((address < ADDR_FLASH_SECTOR_12) && (address >= ADDR_FLASH_SECTOR_11))
|
||||
{
|
||||
sector = FLASH_SECTOR_11;
|
||||
}
|
||||
else
|
||||
{
|
||||
sector = FLASH_SECTOR_11;
|
||||
}
|
||||
|
||||
return sector;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get the next page flash address
|
||||
* @param[in] address: flash address
|
||||
* @retval next page flash address
|
||||
*/
|
||||
/**
|
||||
* @brief 获取下一页flash地址
|
||||
* @param[in] address: flash 地址
|
||||
* @retval 下一页flash地址
|
||||
*/
|
||||
uint32_t get_next_flash_address(uint32_t address)
|
||||
{
|
||||
uint32_t sector = 0;
|
||||
|
||||
if ((address < ADDR_FLASH_SECTOR_1) && (address >= ADDR_FLASH_SECTOR_0))
|
||||
{
|
||||
sector = ADDR_FLASH_SECTOR_1;
|
||||
}
|
||||
else if ((address < ADDR_FLASH_SECTOR_2) && (address >= ADDR_FLASH_SECTOR_1))
|
||||
{
|
||||
sector = ADDR_FLASH_SECTOR_2;
|
||||
}
|
||||
else if ((address < ADDR_FLASH_SECTOR_3) && (address >= ADDR_FLASH_SECTOR_2))
|
||||
{
|
||||
sector = ADDR_FLASH_SECTOR_3;
|
||||
}
|
||||
else if ((address < ADDR_FLASH_SECTOR_4) && (address >= ADDR_FLASH_SECTOR_3))
|
||||
{
|
||||
sector = ADDR_FLASH_SECTOR_4;
|
||||
}
|
||||
else if ((address < ADDR_FLASH_SECTOR_5) && (address >= ADDR_FLASH_SECTOR_4))
|
||||
{
|
||||
sector = ADDR_FLASH_SECTOR_5;
|
||||
}
|
||||
else if ((address < ADDR_FLASH_SECTOR_6) && (address >= ADDR_FLASH_SECTOR_5))
|
||||
{
|
||||
sector = ADDR_FLASH_SECTOR_6;
|
||||
}
|
||||
else if ((address < ADDR_FLASH_SECTOR_7) && (address >= ADDR_FLASH_SECTOR_6))
|
||||
{
|
||||
sector = ADDR_FLASH_SECTOR_7;
|
||||
}
|
||||
else if ((address < ADDR_FLASH_SECTOR_8) && (address >= ADDR_FLASH_SECTOR_7))
|
||||
{
|
||||
sector = ADDR_FLASH_SECTOR_8;
|
||||
}
|
||||
else if ((address < ADDR_FLASH_SECTOR_9) && (address >= ADDR_FLASH_SECTOR_8))
|
||||
{
|
||||
sector = ADDR_FLASH_SECTOR_9;
|
||||
}
|
||||
else if ((address < ADDR_FLASH_SECTOR_10) && (address >= ADDR_FLASH_SECTOR_9))
|
||||
{
|
||||
sector = ADDR_FLASH_SECTOR_10;
|
||||
}
|
||||
else if ((address < ADDR_FLASH_SECTOR_11) && (address >= ADDR_FLASH_SECTOR_10))
|
||||
{
|
||||
sector = ADDR_FLASH_SECTOR_11;
|
||||
}
|
||||
else /*(address < FLASH_END_ADDR) && (address >= ADDR_FLASH_SECTOR_23))*/
|
||||
{
|
||||
sector = FLASH_END_ADDR;
|
||||
}
|
||||
return sector;
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
#ifndef _BSP_FLASH_H
|
||||
#define _BSP_FLASH_H
|
||||
#include "main.h"
|
||||
|
||||
/* Base address of the Flash sectors */
|
||||
#define ADDR_FLASH_SECTOR_0 ((uint32_t)0x08000000) /* Base address of Sector 0, 16 Kbytes */
|
||||
#define ADDR_FLASH_SECTOR_1 ((uint32_t)0x08004000) /* Base address of Sector 1, 16 Kbytes */
|
||||
#define ADDR_FLASH_SECTOR_2 ((uint32_t)0x08008000) /* Base address of Sector 2, 16 Kbytes */
|
||||
#define ADDR_FLASH_SECTOR_3 ((uint32_t)0x0800C000) /* Base address of Sector 3, 16 Kbytes */
|
||||
#define ADDR_FLASH_SECTOR_4 ((uint32_t)0x08010000) /* Base address of Sector 4, 64 Kbytes */
|
||||
#define ADDR_FLASH_SECTOR_5 ((uint32_t)0x08020000) /* Base address of Sector 5, 128 Kbytes */
|
||||
#define ADDR_FLASH_SECTOR_6 ((uint32_t)0x08040000) /* Base address of Sector 6, 128 Kbytes */
|
||||
#define ADDR_FLASH_SECTOR_7 ((uint32_t)0x08060000) /* Base address of Sector 7, 128 Kbytes */
|
||||
#define ADDR_FLASH_SECTOR_8 ((uint32_t)0x08080000) /* Base address of Sector 8, 128 Kbytes */
|
||||
#define ADDR_FLASH_SECTOR_9 ((uint32_t)0x080A0000) /* Base address of Sector 9, 128 Kbytes */
|
||||
#define ADDR_FLASH_SECTOR_10 ((uint32_t)0x080C0000) /* Base address of Sector 10, 128 Kbytes */
|
||||
#define ADDR_FLASH_SECTOR_11 ((uint32_t)0x080E0000) /* Base address of Sector 11, 128 Kbytes */
|
||||
|
||||
#define FLASH_END_ADDR ((uint32_t)0x08100000) /* Base address of Sector 23, 128 Kbytes */
|
||||
|
||||
|
||||
#define ADDR_FLASH_SECTOR_12 ((uint32_t)0x08100000) /* Base address of Sector 12, 16 Kbytes */
|
||||
#define ADDR_FLASH_SECTOR_13 ((uint32_t)0x08104000) /* Base address of Sector 13, 16 Kbytes */
|
||||
#define ADDR_FLASH_SECTOR_14 ((uint32_t)0x08108000) /* Base address of Sector 14, 16 Kbytes */
|
||||
#define ADDR_FLASH_SECTOR_15 ((uint32_t)0x0810C000) /* Base address of Sector 15, 16 Kbytes */
|
||||
#define ADDR_FLASH_SECTOR_16 ((uint32_t)0x08110000) /* Base address of Sector 16, 64 Kbytes */
|
||||
#define ADDR_FLASH_SECTOR_17 ((uint32_t)0x08120000) /* Base address of Sector 17, 128 Kbytes */
|
||||
#define ADDR_FLASH_SECTOR_18 ((uint32_t)0x08140000) /* Base address of Sector 18, 128 Kbytes */
|
||||
#define ADDR_FLASH_SECTOR_19 ((uint32_t)0x08160000) /* Base address of Sector 19, 128 Kbytes */
|
||||
#define ADDR_FLASH_SECTOR_20 ((uint32_t)0x08180000) /* Base address of Sector 20, 128 Kbytes */
|
||||
#define ADDR_FLASH_SECTOR_21 ((uint32_t)0x081A0000) /* Base address of Sector 21, 128 Kbytes */
|
||||
#define ADDR_FLASH_SECTOR_22 ((uint32_t)0x081C0000) /* Base address of Sector 22, 128 Kbytes */
|
||||
#define ADDR_FLASH_SECTOR_23 ((uint32_t)0x081E0000) /* Base address of Sector 23, 128 Kbytes */
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief erase flash
|
||||
* @param[in] address: flash address
|
||||
* @param[in] len: page num
|
||||
* @retval none
|
||||
*/
|
||||
void flash_erase_address(uint32_t address, uint16_t len);
|
||||
|
||||
/**
|
||||
* @brief write data to one page of flash
|
||||
* @param[in] start_address: flash address
|
||||
* @param[in] buf: data point
|
||||
* @param[in] len: data num
|
||||
* @retval success 0, fail -1
|
||||
*/
|
||||
int8_t flash_write_single_address(uint32_t start_address, uint32_t *buf, uint32_t len);
|
||||
|
||||
|
||||
/**
|
||||
* @brief write data to some pages of flash
|
||||
* @param[in] start_address: flash start address
|
||||
* @param[in] end_address: flash end address
|
||||
* @param[in] buf: data point
|
||||
* @param[in] len: data num
|
||||
* @retval success 0, fail -1
|
||||
*/
|
||||
int8_t flash_write_muli_address(uint32_t start_address, uint32_t end_address, uint32_t *buf, uint32_t len);
|
||||
|
||||
/**
|
||||
* @brief read data for flash
|
||||
* @param[in] address: flash address
|
||||
* @param[out] buf: data point
|
||||
* @param[in] len: data num
|
||||
* @retval none
|
||||
*/
|
||||
void flash_read(uint32_t address, uint32_t *buf, uint32_t len);
|
||||
|
||||
/**
|
||||
* @brief get the next page flash address
|
||||
* @param[in] address: flash address
|
||||
* @retval next page flash address
|
||||
*/
|
||||
uint32_t get_next_flash_address(uint32_t address);
|
||||
#endif
|
|
@ -7,44 +7,46 @@
|
|||
|
||||
#define BUFFER_INDEX 0
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief 日志系统初始化
|
||||
*
|
||||
*
|
||||
*/
|
||||
void BSPLogInit();
|
||||
|
||||
/**
|
||||
* @brief 日志功能原型,供下面的LOGI,LOGW,LOGE等使用
|
||||
*
|
||||
*
|
||||
*/
|
||||
#define LOG_PROTO(type,color,format,...) \
|
||||
SEGGER_RTT_printf(BUFFER_INDEX," %s%s"format"\r\n%s", \
|
||||
color, \
|
||||
type, \
|
||||
##__VA_ARGS__, \
|
||||
#define LOG_PROTO(type, color, format, ...) \
|
||||
SEGGER_RTT_printf(BUFFER_INDEX, " %s%s" format "\r\n%s", \
|
||||
color, \
|
||||
type, \
|
||||
##__VA_ARGS__, \
|
||||
RTT_CTRL_RESET)
|
||||
|
||||
/*------下面是日志输出的接口--------*/
|
||||
/*----------------------------------------下面是日志输出的接口-------------------------------------------------*/
|
||||
|
||||
/* 清屏 */
|
||||
#define LOG_CLEAR() SEGGER_RTT_WriteString(0, " "RTT_CTRL_CLEAR)
|
||||
#define LOG_CLEAR() SEGGER_RTT_WriteString(0, " " RTT_CTRL_CLEAR)
|
||||
|
||||
/* 无颜色日志输出 */
|
||||
#define LOG(format,...) LOG_PROTO("","",format,##__VA_ARGS__)
|
||||
#define LOG(format, ...) LOG_PROTO("", "", format, ##__VA_ARGS__)
|
||||
|
||||
/* 有颜色格式日志输出,建议使用这些宏来输出日志 */
|
||||
/**
|
||||
* 有颜色格式日志输出,建议使用这些宏来输出日志
|
||||
* @attention 注意这些接口不支持浮点格式化输出,若有需要,请使用Float2Str()函数进行转换后再打印
|
||||
*/
|
||||
// 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
|
||||
#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
|
||||
#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.
|
||||
*
|
||||
* @attention !! 此函数不支持浮点格式化,若有需要,请使用Float2Str()函数进行转换后再打印 !!
|
||||
*
|
||||
* @param fmt 格式字符串
|
||||
* @param ... 参数列表
|
||||
* @return int 打印的log字符数
|
||||
|
@ -53,7 +55,8 @@ int PrintLog(const char *fmt, ...);
|
|||
|
||||
/**
|
||||
* @brief 利用sprintf(),将float转换为字符串进行打印
|
||||
*
|
||||
* @attention 浮点数需要转换为字符串后才能通过RTT打印
|
||||
*
|
||||
* @param str 转换后的字符串
|
||||
* @param va 待转换的float
|
||||
*/
|
||||
|
|
|
@ -2,11 +2,6 @@
|
|||
|
||||
<p align='right'>neozng1@hnu.edu.cn</p>
|
||||
|
||||
> TODO:
|
||||
>
|
||||
> 1. 在未接入调试器的时候,将日志写入flash中,并提供接口读取
|
||||
> 2. 增加日志分级,提供info、warning、error三个等级的日志
|
||||
|
||||
## 使用说明
|
||||
|
||||
bsp_log是基于segger RTT实现的日志打印模块。
|
||||
|
@ -19,11 +14,11 @@ bsp_log是基于segger RTT实现的日志打印模块。
|
|||
#define LOGERROR(format,...)
|
||||
```
|
||||
|
||||
分别用于输出不同等级的日志。
|
||||
分别用于输出不同等级的日志。注意RTT不支持直接使用`%f`进行浮点格式化,要使用`void Float2Str(char *str, float va);`转化成字符串之后再发送。
|
||||
|
||||
**若想启用RTT,必须通过`launch.json`的`debug-jlink`启动调试(不论使用什么调试器)。**
|
||||
**若想启用RTT,必须通过`launch.json`的`debug-jlink`启动调试(不论使用什么调试器)。** 按照`VSCode+Ozone环境配置`完成配置之后的cmsis dap和daplink是可以支持Jlink全家桶的。
|
||||
|
||||
注意,若你使用的是cmsis-dap和daplink,**请在调试任务启动之后再打开`log`任务。**(均在项目文件夹下的.vsocde/task.json中,有注释自行查看)。
|
||||
另外,若你使用的是cmsis-dap和daplink,**请在 *jlink* 调试任务启动之后再打开`log`任务。**(均在项目文件夹下的.vsocde/task.json中,有注释自行查看)。否则可能出线RTT viewer无法连接客户端的情况。
|
||||
|
||||
在ozone中查看log输出,直接打开console调试任务台和terminal调试中断便可看到调试输出。
|
||||
|
||||
|
@ -35,7 +30,7 @@ bsp_log是基于segger RTT实现的日志打印模块。
|
|||
|
||||
```c
|
||||
int printf_log(const char *fmt, ...);
|
||||
void Float2Str(char *str, float va);
|
||||
void Float2Str(char *str, float va); // 输出浮点需要先用此函数进行转换
|
||||
```
|
||||
|
||||
调用第一个函数,可以通过jlink或dap-link向调试器连接的上位机发送信息,格式和printf相同,示例如下:
|
||||
|
@ -53,8 +48,3 @@ char* str_buff[64];
|
|||
Float2Str(str_buff,current_feedback);
|
||||
printf_log("Motor %d met some problem, error code %d!\n",3,1);
|
||||
```
|
||||
|
||||
或直接通过`%f`格式符直接使用`printf_log()`发送日志,可以设置小数点位数以降低带宽开销。
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ static PWMInstance *pwm_instance[PWM_DEVICE_CNT] = {NULL}; // 所有的pwm insta
|
|||
|
||||
/**
|
||||
* @brief pwm dma传输完成回调函数
|
||||
* @attention 由于HAL库的设计问题,当一个pulse完成(即tim的计数超过比较寄存器)也会调用此函数
|
||||
* 故对于那些开启了PWM的TIM,务必关闭其全局中断,仅保持DMA传输完成中断打开
|
||||
*
|
||||
* @param htim 发生中断的定时器句柄
|
||||
*/
|
||||
|
@ -15,7 +17,7 @@ void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
|
|||
{
|
||||
for (uint8_t i = 0; i < idx; i++)
|
||||
{ // 来自同一个定时器的中断且通道相同
|
||||
if (pwm_instance[i]->htim == htim && htim->Channel == pwm_instance[i]->channel)
|
||||
if (pwm_instance[i]->htim == htim && htim->Channel == (1<<(pwm_instance[i]->channel/4)))
|
||||
{
|
||||
if (pwm_instance[i]->callback) // 如果有回调函数
|
||||
pwm_instance[i]->callback(pwm_instance[i]);
|
||||
|
@ -39,7 +41,7 @@ PWMInstance *PWMRegister(PWM_Init_Config_s *config)
|
|||
pwm->callback = config->callback;
|
||||
pwm->id = config->id;
|
||||
// 启动PWM
|
||||
HAL_TIM_PWM_Start(pwm->htim, pwm->channel);
|
||||
HAL_TIM_PWM_Start_IT(pwm->htim, pwm->channel);
|
||||
__HAL_TIM_SetCompare(pwm->htim, pwm->channel, pwm->pulse); // 设置占空比
|
||||
|
||||
pwm_instance[idx++] = pwm;
|
||||
|
@ -65,7 +67,11 @@ void PWMSetPulse(PWMInstance *pwm, uint32_t pulse)
|
|||
pwm->pulse = pulse;
|
||||
__HAL_TIM_SetCompare(pwm->htim, pwm->channel, pwm->pulse);
|
||||
}
|
||||
|
||||
void PWMSetPeriod(PWMInstance *pwm, uint32_t period)
|
||||
{
|
||||
pwm->period = period;
|
||||
__HAL_TIM_PRESCALER(pwm->htim, pwm->period);
|
||||
}
|
||||
/* 只是对HAL的函数进行了形式上的封装 */
|
||||
void PWMStartDMA(PWMInstance *pwm, uint32_t *pData, uint32_t Size)
|
||||
{
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
*
|
||||
*/
|
||||
#include "bsp_usart.h"
|
||||
#include "bsp_log.h"
|
||||
#include "stdlib.h"
|
||||
#include "memory.h"
|
||||
|
||||
|
@ -38,7 +39,13 @@ USARTInstance *USARTRegister(USART_Init_Config_s *init_config)
|
|||
{
|
||||
if (idx >= DEVICE_USART_CNT) // 超过最大实例数
|
||||
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));
|
||||
memset(instance, 0, sizeof(USARTInstance));
|
||||
|
||||
|
@ -75,14 +82,10 @@ void USARTSend(USARTInstance *_instance, uint8_t *send_buf, uint16_t send_size,
|
|||
/* 串口发送时,gstate会被设为BUSY_TX */
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
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_DMA_DISABLE_IT(usart_instance[i]->usart_handle->hdmarx, DMA_IT_HT);
|
||||
LOGWARNING("[bsp_usart] USART error callback triggered, instance idx [%d]", i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
|
||||
需要在串口实例下设定接收的数据包的长度,实例对应的串口硬件(通过`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[]`访问串口收到的数据。
|
||||
|
||||
## 代码结构
|
||||
|
||||
|
|
|
@ -11,16 +11,17 @@
|
|||
|
||||
#include "bsp_usb.h"
|
||||
#include "bsp_log.h"
|
||||
#include "bsp_dwt.h"
|
||||
|
||||
static uint8_t *bsp_usb_rx_buffer; // 接收到的数据会被放在这里,buffer size为2048
|
||||
// 注意usb单个数据包(Full speed模式下)最大为64byte,超出可能会出现丢包情况
|
||||
|
||||
uint8_t *USBInit(USB_Init_Config_s usb_conf)
|
||||
{
|
||||
// 上电后重新枚举usb设备
|
||||
LOGINFO("USB init success");
|
||||
// usb的软件复位(模拟拔插)在usbd_conf.c中的HAL_PCD_MspInit()中
|
||||
bsp_usb_rx_buffer = CDCInitRxbufferNcallback(usb_conf.tx_cbk, usb_conf.rx_cbk); // 获取接收数据指针
|
||||
// usb的接收回调函数会在这里被设置,并将数据保存在bsp_usb_rx_buffer中
|
||||
LOGINFO("USB init success");
|
||||
return bsp_usb_rx_buffer;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 uint8_t tx[2];
|
||||
tx[0] = reg;
|
||||
tx[1] = data;
|
||||
uint8_t tx[2] = {reg, data};
|
||||
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 uint8_t tx[2];
|
||||
tx[0] = reg;
|
||||
tx[1] = data;
|
||||
uint8_t tx[2] = {reg, data};
|
||||
SPITransmit(bmi088->spi_gyro, tx, 2);
|
||||
}
|
||||
// -------------------------以上为私有函数,封装了BMI088寄存器读写函数,blocking--------------------------------//
|
||||
|
||||
// -------------------------以下为私有函数,用于初始化BMI088acc和gyro的硬件和配置--------------------------------//
|
||||
#define REG 0
|
||||
#define DATA 1
|
||||
#define ERROR 2
|
||||
#define BMI088REG 0
|
||||
#define BMI088DATA 1
|
||||
#define BMI088ERROR 2
|
||||
// BMI088初始化配置数组for accel,第一列为reg地址,第二列为写入的配置值,第三列为错误码(如果出错)
|
||||
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加速度计,提高可读性分拆功能
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
|
@ -130,14 +126,14 @@ static uint8_t BMI088AccelInit(BMI088Instance *bmi088)
|
|||
// 使用sizeof而不是magic number,这样如果修改了数组大小,不用修改这里的代码;或者使用宏定义
|
||||
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];
|
||||
data = BMI088_Accel_Init_Table[i][DATA];
|
||||
reg = BMI088_Accel_Init_Table[i][BMI088REG];
|
||||
data = BMI088_Accel_Init_Table[i][BMI088DATA];
|
||||
BMI088AccelWriteSingleReg(bmi088, reg, data); // 写入寄存器
|
||||
DWT_Delay(0.01);
|
||||
BMI088AccelRead(bmi088, reg, &data, 1); // 写完之后立刻读回检查
|
||||
DWT_Delay(0.01);
|
||||
if (data != BMI088_Accel_Init_Table[i][DATA])
|
||||
error |= BMI088_Accel_Init_Table[i][ERROR];
|
||||
if (data != BMI088_Accel_Init_Table[i][BMI088DATA])
|
||||
error |= BMI088_Accel_Init_Table[i][BMI088ERROR];
|
||||
//{i--;} 可以设置retry次数,如果retry次数用完了,则返回error
|
||||
}
|
||||
return error;
|
||||
|
@ -147,7 +143,7 @@ static uint8_t BMI088AccelInit(BMI088Instance *bmi088)
|
|||
* @brief 初始化BMI088陀螺仪,提高可读性分拆功能
|
||||
*
|
||||
* @param bmi088 待初始化的BMI088实例
|
||||
* @return uint8_t ERROR CODE
|
||||
* @return uint8_t BMI088ERROR CODE
|
||||
*/
|
||||
static uint8_t BMI088GyroInit(BMI088Instance *bmi088)
|
||||
{
|
||||
|
@ -169,14 +165,14 @@ static uint8_t BMI088GyroInit(BMI088Instance *bmi088)
|
|||
// 使用sizeof而不是magic number,这样如果修改了数组大小,不用修改这里的代码;或者使用宏定义
|
||||
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];
|
||||
data = BMI088_Gyro_Init_Table[i][DATA];
|
||||
reg = BMI088_Gyro_Init_Table[i][BMI088REG];
|
||||
data = BMI088_Gyro_Init_Table[i][BMI088DATA];
|
||||
BMI088GyroWriteSingleReg(bmi088, reg, data); // 写入寄存器
|
||||
DWT_Delay(0.001);
|
||||
BMI088GyroRead(bmi088, reg, &data, 1); // 写完之后立刻读回对应寄存器检查是否写入成功
|
||||
DWT_Delay(0.001);
|
||||
if (data != BMI088_Gyro_Init_Table[i][DATA])
|
||||
error |= BMI088_Gyro_Init_Table[i][ERROR];
|
||||
if (data != BMI088_Gyro_Init_Table[i][BMI088DATA])
|
||||
error |= BMI088_Gyro_Init_Table[i][BMI088ERROR];
|
||||
//{i--;} 可以设置retry次数,尝试重新写入.如果retry次数用完了,则返回error
|
||||
}
|
||||
|
||||
|
@ -386,7 +382,7 @@ void BMI088CalibrateIMU(BMI088Instance *_bmi088)
|
|||
BMI088Instance *BMI088Register(BMI088_Init_Config_s *config)
|
||||
{
|
||||
// 申请内存
|
||||
BMI088Instance *bmi088_instance = (BMI088Instance *)zero_malloc(sizeof(BMI088Instance));
|
||||
BMI088Instance *bmi088_instance = (BMI088Instance *)zmalloc(sizeof(BMI088Instance));
|
||||
// 从右向左赋值,让bsp instance保存指向bmi088_instance的指针(父指针),便于在底层中断中访问bmi088_instance
|
||||
config->acc_int_config.id =
|
||||
config->gyro_int_config.id =
|
||||
|
|
|
@ -7,24 +7,24 @@
|
|||
```c
|
||||
BMI088_Init_Config_s imu_config = {
|
||||
.spi_acc_config={
|
||||
.GPIOx=GPIOC,
|
||||
.GPIOx=GPIOA,
|
||||
.GPIOx=GPIO_PIN_4,
|
||||
.spi_handle=&hspi1,
|
||||
},
|
||||
.spi_gyro_config={
|
||||
.GPIOx=GPIOC,
|
||||
.GPIOx=GPIO_PIN_4,
|
||||
.GPIOx=GPIOB,
|
||||
.GPIOx=GPIO_PIN_0,
|
||||
.spi_handle=&hspi1,
|
||||
},
|
||||
.acc_int_config={
|
||||
.exti_mode=EXTI_TRIGGER_FALLING,
|
||||
.GPIO_Pin=GPIO_PIN_10,
|
||||
.GPIOx=GPIOA,
|
||||
.GPIO_Pin=GPIO_PIN_4,
|
||||
.GPIOx=GPIOC,
|
||||
},
|
||||
.gyro_int_config={
|
||||
.exti_mode=EXTI_TRIGGER_FALLING,
|
||||
.GPIO_Pin=GPIO_PIN_11,
|
||||
.GPIOx=GPIOA,
|
||||
.GPIO_Pin=GPIO_PIN_5,
|
||||
.GPIOx=GPIOC,
|
||||
},
|
||||
.heat_pid_config={
|
||||
.Kp=0.0f,
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
#include "bsp_pwm.h"
|
||||
#include "buzzer.h"
|
||||
#include "bsp_dwt.h"
|
||||
|
||||
static PWMInstance *buzzer;
|
||||
|
||||
static alarm_level_e now_alarm_level = ALARM_OFFLINE;
|
||||
|
||||
void BuzzerOn(PWMInstance *buzzer );
|
||||
/**
|
||||
*
|
||||
* @brief 蜂鸣器报警函数
|
||||
* @param alarm_level 报警级别
|
||||
*/
|
||||
void BuzzerPlay(alarm_level_e alarm_level)
|
||||
{
|
||||
static alarm_level_e last_alarm_level = ALARM_LEVEL_LOW;
|
||||
|
||||
if(((int)DWT_GetTimeline_s() % 5)<1) //每5秒检查一次
|
||||
{
|
||||
last_alarm_level = ALARM_LEVEL_LOW;
|
||||
now_alarm_level = ALARM_OFFLINE;
|
||||
}
|
||||
|
||||
if(last_alarm_level <= now_alarm_level) //如果当前报警级别大于等于上一次报警级别,则更新报警级别
|
||||
{
|
||||
now_alarm_level = alarm_level;
|
||||
}
|
||||
last_alarm_level = alarm_level;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 蜂鸣器初始化
|
||||
*
|
||||
*/
|
||||
void buzzer_init()
|
||||
{
|
||||
PWM_Init_Config_s buzzer_config = {
|
||||
.htim = &htim4,
|
||||
.channel= TIM_CHANNEL_3,
|
||||
.period = 1,
|
||||
.pulse = 10000,
|
||||
.callback = BuzzerOn,
|
||||
};
|
||||
buzzer = PWMRegister(&buzzer_config);
|
||||
}
|
||||
/**
|
||||
* @brief 开启蜂鸣器
|
||||
*
|
||||
* @param buzzer
|
||||
*/
|
||||
//*@todo: 优化报警声,应类似D__,DDD,B__,BBB等报警声
|
||||
void BuzzerOn(PWMInstance *buzzer )
|
||||
{
|
||||
switch (now_alarm_level)
|
||||
{
|
||||
case ALARM_LEVEL_LOW:
|
||||
PWMSetPeriod(buzzer, 1);
|
||||
PWMSetPulse(buzzer, 10000);
|
||||
break;
|
||||
case ALARM_LEVEL_BELOW_MEDIUM:
|
||||
PWMSetPeriod(buzzer, 2);
|
||||
PWMSetPulse(buzzer, 10000);
|
||||
break;
|
||||
case ALARM_LEVEL_MEDIUM:
|
||||
PWMSetPeriod(buzzer, 3);
|
||||
PWMSetPulse(buzzer, 10000);
|
||||
break;
|
||||
case ALARM_LEVEL_ABOVE_MEDIUM:
|
||||
PWMSetPeriod(buzzer, 4);
|
||||
PWMSetPulse(buzzer, 10000);
|
||||
break;
|
||||
case ALARM_LEVEL_HIGH:
|
||||
PWMSetPeriod(buzzer, 5);
|
||||
PWMSetPulse(buzzer, 10000);
|
||||
break;
|
||||
|
||||
default:
|
||||
PWMSetPulse(buzzer, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef BUZZER_H
|
||||
#define BUZZER_H
|
||||
#include "daemon.h"
|
||||
void buzzer_init();
|
||||
|
||||
|
||||
#endif // !BUZZER_H
|
|
@ -23,9 +23,7 @@
|
|||
#define user_malloc malloc
|
||||
#endif
|
||||
|
||||
uint8_t GlobalDebugMode = 7;
|
||||
|
||||
void *zero_malloc(size_t size)
|
||||
void *zmalloc(size_t size)
|
||||
{
|
||||
void *ptr = malloc(size);
|
||||
memset(ptr, 0, size);
|
||||
|
@ -207,3 +205,10 @@ float AverageFilter(float new_data, float *buf, uint8_t len)
|
|||
sum += new_data;
|
||||
return sum / len;
|
||||
}
|
||||
|
||||
void MatInit(mat *m, uint8_t row, uint8_t col)
|
||||
{
|
||||
m->numCols = col;
|
||||
m->numRows = row;
|
||||
m->pData = (float *)zmalloc(row * col * sizeof(float));
|
||||
}
|
||||
|
|
|
@ -13,18 +13,13 @@
|
|||
#ifndef _USER_LIB_H
|
||||
#define _USER_LIB_H
|
||||
|
||||
|
||||
#include "stdint.h"
|
||||
#include "main.h"
|
||||
#include "cmsis_os.h"
|
||||
#include "stm32f407xx.h"
|
||||
#include "arm_math.h"
|
||||
|
||||
|
||||
#define msin(x) (arm_sin_f32(x))
|
||||
#define mcos(x) (arm_cos_f32(x))
|
||||
|
||||
|
||||
extern uint8_t GlobalDebugMode;
|
||||
|
||||
#ifndef user_malloc
|
||||
#ifdef _CMSIS_OS_H
|
||||
#define user_malloc pvPortMalloc
|
||||
|
@ -33,6 +28,18 @@ extern uint8_t GlobalDebugMode;
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#define msin(x) (arm_sin_f32(x))
|
||||
#define mcos(x) (arm_cos_f32(x))
|
||||
|
||||
typedef arm_matrix_instance_f32 mat;
|
||||
// 若运算速度不够,可以使用q31代替f32,但是精度会降低
|
||||
#define MatAdd arm_mat_add_f32
|
||||
#define MatSubtract arm_mat_sub_f32
|
||||
#define MatMultiply arm_mat_mult_f32
|
||||
#define MatTranspose arm_mat_trans_f32
|
||||
#define MatInverse arm_mat_inverse_f32
|
||||
void MatInit(mat *m, uint8_t row, uint8_t col);
|
||||
|
||||
/* boolean type definitions */
|
||||
#ifndef TRUE
|
||||
#define TRUE 1 /**< boolean true */
|
||||
|
@ -42,12 +49,6 @@ extern uint8_t GlobalDebugMode;
|
|||
#define FALSE 0 /**< boolean fails */
|
||||
#endif
|
||||
|
||||
/* math relevant */
|
||||
/* radian coefficient */
|
||||
#ifndef RADIAN_COEF
|
||||
#define RADIAN_COEF 57.295779513f
|
||||
#endif
|
||||
|
||||
/* circumference ratio */
|
||||
#ifndef PI
|
||||
#define PI 3.14159265354f
|
||||
|
@ -89,7 +90,7 @@ extern uint8_t GlobalDebugMode;
|
|||
* @param size 分配大小
|
||||
* @return void*
|
||||
*/
|
||||
void *zero_malloc(size_t size);
|
||||
void *zmalloc(size_t size);
|
||||
|
||||
// <20><><EFBFBD>ٿ<EFBFBD><D9BF><EFBFBD>
|
||||
float Sqrt(float x);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "stdlib.h"
|
||||
#include "crc8.h"
|
||||
#include "bsp_dwt.h"
|
||||
#include "bsp_log.h"
|
||||
|
||||
/**
|
||||
* @brief 重置CAN comm的接收状态和buffer
|
||||
|
@ -59,7 +60,7 @@ static void CANCommRxCallback(CANInstance *_instance)
|
|||
if (comm->raw_recvbuf[comm->recv_buf_len - 2] == crc_8(comm->raw_recvbuf + 2, comm->recv_data_len))
|
||||
{ // 数据量大的话考虑使用DMA
|
||||
memcpy(comm->unpacked_recv_data, comm->raw_recvbuf + 2, comm->recv_data_len);
|
||||
comm->update_flag = 1; // 数据更新flag置为1
|
||||
comm->update_flag = 1; // 数据更新flag置为1
|
||||
DaemonReload(comm->comm_daemon); // 重载daemon,避免数据更新后一直不被读取而导致数据更新不及时
|
||||
}
|
||||
}
|
||||
|
@ -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 *ins = (CANCommInstance *)malloc(sizeof(CANCommInstance));
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "bsp_dwt.h" // 后续通过定时器来计时?
|
||||
#include "stdlib.h"
|
||||
#include "memory.h"
|
||||
#include "buzzer.h"
|
||||
|
||||
// 用于保存所有的daemon instance
|
||||
static DaemonInstance *daemon_instances[DAEMON_MX_CNT] = {NULL};
|
||||
|
@ -13,9 +14,13 @@ DaemonInstance *DaemonRegister(Daemon_Init_Config_s *config)
|
|||
memset(instance, 0, sizeof(DaemonInstance));
|
||||
|
||||
instance->owner_id = config->owner_id;
|
||||
instance->reload_count = config->reload_count == 0 ? 100 : config->reload_count;
|
||||
instance->reload_count = config->reload_count == 0 ? 100 : config->reload_count; // 默认值为100
|
||||
instance->callback = config->callback;
|
||||
instance->temp_count = config->init_count == 0 ? 100 : config->init_count; // 默认值为100,初始计数
|
||||
|
||||
instance->alarm_state = config->alarm_state;
|
||||
instance->alarm_level = config->alarm_level;
|
||||
instance->temp_count = config->reload_count;
|
||||
daemon_instances[idx++] = instance;
|
||||
return instance;
|
||||
}
|
||||
|
@ -36,6 +41,7 @@ void DaemonTask()
|
|||
DaemonInstance *dins; // 提高可读性同时降低访存开销
|
||||
for (size_t i = 0; i < idx; ++i)
|
||||
{
|
||||
|
||||
dins = daemon_instances[i];
|
||||
if (dins->temp_count > 0) // 如果计数器还有值,说明上一次喂狗后还没有超时,则计数器减一
|
||||
dins->temp_count--;
|
||||
|
@ -43,6 +49,11 @@ void DaemonTask()
|
|||
{
|
||||
dins->callback(dins->owner_id); // module内可以将owner_id强制类型转换成自身类型从而调用特定module的offline callback
|
||||
// @todo 为蜂鸣器/led等增加离线报警的功能,非常关键!
|
||||
if(dins->alarm_state == ALARM_ON)
|
||||
{
|
||||
BuzzerPlay(dins->alarm_level);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,18 +2,34 @@
|
|||
#define MONITOR_H
|
||||
|
||||
#include "stdint.h"
|
||||
#include "string.h"
|
||||
|
||||
#define DAEMON_MX_CNT 64
|
||||
|
||||
/* 模块离线处理函数指针 */
|
||||
typedef void (*offline_callback)(void *);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ALARM_OFF = 0,
|
||||
ALARM_ON = 1,
|
||||
}alarm_state_e;
|
||||
typedef enum
|
||||
{
|
||||
ALARM_LEVEL_LOW = 0,
|
||||
ALARM_LEVEL_BELOW_MEDIUM = 1,
|
||||
ALARM_LEVEL_MEDIUM = 2,
|
||||
ALARM_LEVEL_ABOVE_MEDIUM = 3,
|
||||
ALARM_LEVEL_HIGH = 4,
|
||||
ALARM_OFFLINE = 5,
|
||||
}alarm_level_e;
|
||||
/* daemon结构体定义 */
|
||||
typedef struct daemon_ins
|
||||
{
|
||||
uint16_t reload_count; // 重载值
|
||||
offline_callback callback; // 异常处理函数,当模块发生异常时会被调用
|
||||
|
||||
alarm_state_e alarm_state; // 蜂鸣器状态
|
||||
alarm_level_e alarm_level; //警报级别
|
||||
|
||||
uint16_t temp_count; // 当前值,减为零说明模块离线或异常
|
||||
void *owner_id; // daemon实例的地址,初始化的时候填入
|
||||
} DaemonInstance;
|
||||
|
@ -22,7 +38,11 @@ typedef struct daemon_ins
|
|||
typedef struct
|
||||
{
|
||||
uint16_t reload_count; // 实际上这是app唯一需要设置的值?
|
||||
uint16_t init_count; // 上线等待时间,有些模块需要收到主控的指令才会反馈报文,或pc等需要开机时间
|
||||
offline_callback callback; // 异常处理函数,当模块发生异常时会被调用
|
||||
alarm_state_e alarm_state; // 蜂鸣器状态
|
||||
alarm_level_e alarm_level; //警报级别
|
||||
|
||||
void *owner_id; // id取拥有daemon的实例的地址,如DJIMotorInstance*,cast成void*类型
|
||||
} Daemon_Init_Config_s;
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "BMI088reg.h"
|
||||
#include "BMI088Middleware.h"
|
||||
#include "bsp_dwt.h"
|
||||
#include "bsp_log.h"
|
||||
#include <math.h>
|
||||
|
||||
#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();
|
||||
do
|
||||
{
|
||||
if (DWT_GetTimeline_s() - startTime > 10)
|
||||
if (DWT_GetTimeline_s() - startTime > 12)
|
||||
{
|
||||
// <20><>????
|
||||
bmi088->GyroOffset[0] = GxOFFSET;
|
||||
|
@ -137,6 +138,7 @@ void Calibrate_MPU_Offset(IMU_Data_t *bmi088)
|
|||
bmi088->GyroOffset[2] = GzOFFSET;
|
||||
bmi088->gNorm = gNORM;
|
||||
bmi088->TempWhenCali = 40;
|
||||
LOGERROR("[BMI088] Calibrate Failed! Use offline params");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -206,7 +208,11 @@ void Calibrate_MPU_Offset(IMU_Data_t *bmi088)
|
|||
gyroDiff[0] > 0.15f ||
|
||||
gyroDiff[1] > 0.15f ||
|
||||
gyroDiff[2] > 0.15f)
|
||||
{
|
||||
LOGWARNING("[bmi088] calibration was interrupted\n");
|
||||
break;
|
||||
}
|
||||
|
||||
DWT_Delay(0.0005);
|
||||
}
|
||||
|
||||
|
@ -252,7 +258,10 @@ uint8_t bmi088_accel_init(void)
|
|||
|
||||
// check the "who am I"
|
||||
if (res != BMI088_ACC_CHIP_ID_VALUE)
|
||||
{
|
||||
LOGERROR("[bmi088] Can not read bmi088 acc chip id");
|
||||
return BMI088_NO_SENSOR;
|
||||
}
|
||||
|
||||
// set accel sonsor config and check
|
||||
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"
|
||||
if (res != BMI088_GYRO_CHIP_ID_VALUE)
|
||||
{
|
||||
LOGERROR("[bmi088] Can not read bmi088 gyro chip id");
|
||||
return BMI088_NO_SENSOR;
|
||||
}
|
||||
|
||||
// set gyro sonsor config and check
|
||||
for (write_reg_num = 0; write_reg_num < BMI088_WRITE_GYRO_REG_NUM; write_reg_num++)
|
||||
|
|
|
@ -8,7 +8,7 @@ static LEDInstance *bsp_led_ins[LED_MAX_NUM] = {NULL};
|
|||
|
||||
LEDInstance *LEDRegister(LED_Init_Config_s *led_config)
|
||||
{
|
||||
LEDInstance *led_ins = (LEDInstance *)zero_malloc(sizeof(LEDInstance));
|
||||
LEDInstance *led_ins = (LEDInstance *)zmalloc(sizeof(LEDInstance));
|
||||
// 剩下的值暂时都被置零
|
||||
led_ins->led_pwm = PWMRegister(&led_config->pwm_config);
|
||||
led_ins->led_switch = led_config->init_swtich;
|
||||
|
|
|
@ -10,11 +10,13 @@
|
|||
*/
|
||||
#include "master_process.h"
|
||||
#include "seasky_protocol.h"
|
||||
#include "daemon.h"
|
||||
#include "bsp_log.h"
|
||||
#include "robot_def.h"
|
||||
|
||||
static Vision_Recv_s recv_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)
|
||||
{
|
||||
|
@ -30,13 +32,26 @@ void VisionSetAltitude(float yaw, float pitch, float 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
|
||||
|
||||
#include "bsp_usart.h"
|
||||
#include "daemon.h"
|
||||
|
||||
static USARTInstance *vision_usart_instance;
|
||||
static DaemonInstance *vision_daemon_instance;
|
||||
|
||||
/**
|
||||
* @brief 接收解包回调函数,将在bsp_usart.c中被usart rx callback调用
|
||||
|
@ -51,21 +66,8 @@ static void DecodeVision()
|
|||
// 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)
|
||||
{
|
||||
#ifdef VISION_USE_UART
|
||||
USART_Init_Config_s conf;
|
||||
conf.module_callback = DecodeVision;
|
||||
conf.recv_buff_size = VISION_RECV_SIZE;
|
||||
|
@ -79,7 +81,6 @@ Vision_Recv_s *VisionInit(UART_HandleTypeDef *_handle)
|
|||
.reload_count = 10,
|
||||
};
|
||||
vision_daemon_instance = DaemonRegister(&daemon_conf);
|
||||
#endif // VISION_USE_UART
|
||||
|
||||
return &recv_data;
|
||||
}
|
||||
|
@ -125,9 +126,17 @@ static void DecodeVision(uint16_t recv_len)
|
|||
Vision_Recv_s *VisionInit(UART_HandleTypeDef *_handle)
|
||||
{
|
||||
UNUSED(_handle); // 仅为了消除警告
|
||||
USB_Init_Config_s conf = {0};
|
||||
conf.rx_cbk = DecodeVision;
|
||||
USB_Init_Config_s conf = {.rx_cbk = DecodeVision};
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,14 +4,15 @@
|
|||
#include "bsp_log.h"
|
||||
|
||||
static uint8_t idx = 0; // register idx,是该文件的全局电机索引,在注册时使用
|
||||
|
||||
/* 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专门负责发送
|
||||
* 该变量将在 DJIMotorControl() 中使用,分组在 MotorSenderGrouping()中进行
|
||||
*
|
||||
* @note 因为只用于发送,所以不需要在bsp_can中注册
|
||||
*
|
||||
* C610(m2006)/C620(m3508):0x1ff,0x200;
|
||||
* GM6020:0x1ff,0x2ff
|
||||
* 反馈(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)
|
||||
{
|
||||
LOGERROR("[dji_motor] ID crash. Check in debug mode, add dji_motor_instance to watch to get more information."); // 后续可以把id和CAN打印出来
|
||||
while (1)
|
||||
; // 6020的id 1-4和2006/3508的id 5-8会发生冲突(若有注册,即1!5,2!6,3!7,4!8) (1!5!,LTC! (((不是)
|
||||
LOGERROR("[dji_motor] ID crash. Check in debug mode, add dji_motor_instance to watch to get more information.");
|
||||
uint16_t can_bus = config->can_handle == &hcan1 ? 1 : 2;
|
||||
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;
|
||||
|
@ -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)
|
||||
{
|
||||
LOGERROR("[dji_motor] ID crash. Check in debug mode, add dji_motor_instance to watch to get more information.");
|
||||
while (1)
|
||||
; // 6020的id 1-4和2006/3508的id 5-8会发生冲突(若有注册,即1!5,2!6,3!7,4!8)
|
||||
uint16_t can_bus = config->can_handle == &hcan1 ? 1 : 2;
|
||||
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;
|
||||
|
||||
default: // other motors should not be registered here
|
||||
LOGERROR("You must not register other motors using the API of DJI motor.");
|
||||
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)
|
||||
{
|
||||
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 = {
|
||||
.callback = DJIMotorLostCallback,
|
||||
.owner_id = instance,
|
||||
.reload_count = 1, // 10ms未收到数据则丢失
|
||||
.reload_count = 2, // 20ms未收到数据则丢失
|
||||
};
|
||||
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)
|
||||
{
|
||||
if (loop == ANGLE_LOOP)
|
||||
{
|
||||
motor->motor_settings.angle_feedback_source = type;
|
||||
}
|
||||
else if (loop == SPEED_LOOP)
|
||||
{
|
||||
motor->motor_settings.speed_feedback_source = type;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGERROR("[dji_motor] loop type error, check memory access and func param"); // 检查是否传入了正确的LOOP类型,或发生了指针越界
|
||||
}
|
||||
}
|
||||
|
||||
void DJIMotorStop(DJIMotorInstance *motor)
|
||||
|
@ -299,11 +298,9 @@ void DJIMotorControl()
|
|||
sender_assignment[group].tx_buff[2 * num] = (uint8_t)(set >> 8); // 低八位
|
||||
sender_assignment[group].tx_buff[2 * num + 1] = (uint8_t)(set & 0x00ff); // 高八位
|
||||
|
||||
// 电机是否停止运行
|
||||
// 若该电机处于停止状态,直接将buff置零
|
||||
if (motor->stop_flag == MOTOR_STOP)
|
||||
{ // 若该电机处于停止状态,直接将buff置零
|
||||
memset(sender_assignment[group].tx_buff + 2 * num, 0, 16u);
|
||||
}
|
||||
}
|
||||
|
||||
// 遍历flag,检查是否要发送这一帧报文
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "string.h"
|
||||
#include "daemon.h"
|
||||
#include "stdlib.h"
|
||||
#include "bsp_log.h"
|
||||
|
||||
static uint8_t idx;
|
||||
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]);
|
||||
measure->real_current = CURRENT_SMOOTH_COEF * uint_to_float(tmp, T_MIN, T_MAX, 12) +
|
||||
(1 - CURRENT_SMOOTH_COEF) * measure->real_current;
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void HTMotorLostCallback(void *motor_ptr)
|
||||
{
|
||||
HTMotorInstance *motor = (HTMotorInstance *)motor_ptr;
|
||||
if (motor->stop_flag == MOTOR_STOP)
|
||||
return;
|
||||
LOGWARNING("[ht_motor] motor %d lost\n", motor->motor_can_instace->tx_id);
|
||||
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电机说明
|
||||
CANTransmit(motor->motor_can_instace, 1);
|
||||
DWT_Delay(0.005);
|
||||
HTMotorSetMode(CMD_ZERO_POSITION, motor);
|
||||
HTMotorSetMode(CMD_ZERO_POSITION, motor); // sb 玩意校准完了编码器也不为0
|
||||
DWT_Delay(0.005);
|
||||
// HTMotorSetMode(CMD_MOTOR_MODE, motor);
|
||||
}
|
||||
|
@ -215,7 +213,7 @@ void HTMotorControlInit()
|
|||
char ht_id_buff[2] = {0};
|
||||
__itoa(i, ht_id_buff, 10);
|
||||
strcat(ht_task_name, ht_id_buff); // 似乎没什么吊用,osthreaddef会把第一个变量当作宏字符串传入,作为任务名
|
||||
// todo 还需要一个更优雅的方案来区分不同的电机任务
|
||||
// @todo 还需要一个更优雅的方案来区分不同的电机任务
|
||||
osThreadDef(ht_task_name, HTMotorTask, osPriorityNormal, 0, 128);
|
||||
ht_task_handle[i] = osThreadCreate(osThread(ht_task_name), ht_motor_instance[i]);
|
||||
}
|
||||
|
|
|
@ -40,3 +40,5 @@ static void HTMotorDecode(CANInstance *motor_can)
|
|||
}
|
||||
}
|
||||
```
|
||||
|
||||
第一次收到数据时默认电机处于限位处,将速度和角度都设置为零,记录当前的编码器数据,之后每次收到都减去该值.
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "general_def.h"
|
||||
#include "daemon.h"
|
||||
#include "bsp_dwt.h"
|
||||
#include "bsp_log.h"
|
||||
|
||||
static uint8_t idx;
|
||||
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;
|
||||
}
|
||||
|
||||
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 *motor = (LKMotorInstance *)malloc(sizeof(LKMotorInstance));
|
||||
|
@ -75,7 +82,7 @@ LKMotorInstance *LKMotorInit(Motor_Init_Config_s *config)
|
|||
Daemon_Init_Config_s daemon_config = {
|
||||
.callback = NULL,
|
||||
.owner_id = motor,
|
||||
.reload_count = 5, // 0.05秒
|
||||
.reload_count = 5, // 50ms
|
||||
};
|
||||
motor->daemon = DaemonRegister(&daemon_config);
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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
|
|
@ -1,3 +0,0 @@
|
|||
# ps_handle
|
||||
|
||||
提供ps手柄的支持,其通信协议和spi类似,可以使用bsp_spi来兼容.待编写.
|
|
@ -15,8 +15,9 @@
|
|||
#include "bsp_usart.h"
|
||||
#include "task.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 DaemonInstance *referee_daemon; // 裁判系统守护进程
|
||||
|
@ -114,6 +115,7 @@ static void RefereeRxCallback()
|
|||
static void RefereeLostCallback(void *arg)
|
||||
{
|
||||
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;
|
||||
conf.module_callback = RefereeRxCallback;
|
||||
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);
|
||||
|
||||
Daemon_Init_Config_s daemon_conf = {
|
||||
|
@ -143,5 +145,5 @@ void RefereeSend(uint8_t *send, uint16_t tx_len)
|
|||
{
|
||||
static TickType_t xLastWakeTime;
|
||||
USARTSend(referee_usart_instance, send, tx_len, USART_TRANSFER_DMA);
|
||||
vTaskDelayUntil(&xLastWakeTime, 120);
|
||||
vTaskDelayUntil(&xLastWakeTime, 120); // 裁判系统接收ui数据和多机通信最大支持频率为10Hz
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "memory.h"
|
||||
#include "stdlib.h"
|
||||
#include "daemon.h"
|
||||
#include "bsp_log.h"
|
||||
|
||||
#define REMOTE_CONTROL_FRAME_SIZE 18u // 遥控器接收的buffer大小
|
||||
|
||||
|
@ -104,6 +105,7 @@ static void RCLostCallback(void *id)
|
|||
{
|
||||
memset(rc_ctrl, 0, sizeof(rc_ctrl)); // 清空遥控器数据
|
||||
USARTServiceInit(rc_usart_instance); // 尝试重新启动接收
|
||||
LOGWARNING("[rc] remote control lost");
|
||||
}
|
||||
|
||||
RC_ctrl_t *RemoteControlInit(UART_HandleTypeDef *rc_usart_handle)
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
# 利用Ozone进行model-based PID tunning
|
||||
|
||||
Ozone的实时变量可视化监测(示波器)功能可以很好地帮助我们观察控制器在时域的表现,典型的有上升时间、超调量和稳态时间等。
|
||||
|
||||
## 调试顺序
|
||||
|
||||
先内环,后外环。若有已知的外部扰动如阻力、重力等可以在**保持kp不变**的情况下添加积分环节,并查看达到稳态时积分的输出,该输出值可以作为**前馈**作用通过feedforward_ptr一同送入下一个串级控制器。
|
Loading…
Reference in New Issue