添加了大量调试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

@@ -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;
}

View File

@@ -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)
{
}
;
}

View File

@@ -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_ */

View File

@@ -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;
```

View File

@@ -36,11 +36,11 @@ void BSPLogInit();
/* 有颜色格式日志输出,建议使用这些宏来输出日志 */
// 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.

View File

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

View File

@@ -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;
}
}

View File

@@ -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[]`访问串口收到的数据。
## 代码结构

View File

@@ -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;
}