ikun之家

  • 欢迎来到ikun之家
  • 项目分类
  • 站点简介
「RTFM, then Build.」
第一个『Hello World』在屏幕上闪烁,最后一个『Hello World』向火星问好
  1. 首页
  2. 项目分类
  3. 硬件项目
  4. 正文

GB-IFD&DSP调试记录

2026年5月7日 237点热度 0人点赞

ARM-F429软件调试

AD9516调试时发现通信时误码,降速后正常,推测串接的1k电阻太大了,暂时未做处理,降速运行,将寄存器写入后,AD9516运行正常,各路时钟输出均正常


程序代码编写

踩坑日志:

1、定时器中断:如果先开启HAL_TIM_Base_Start(&htimX),再开启HAL_TIM_Base_Start_IT(&htimX),那么就会导致中断无法开启,因为运行第一个函数的时候已经将状态设置为Busy,运行第二个函数时就已经无法生效了。

1. HAL_TIM_Base_Start(&htim2) 执行了什么:

  • 检查状态:它首先检查 htim2.State 是否等于 HAL_TIM_STATE_READY。
  • 锁定状态:如果准备好了,它会把状态修改为 HAL_TIM_STATE_BUSY。
  • 开启硬件:设置寄存器,让定时器开始数数。

2. HAL_TIM_Base_Start_IT(&htim2) 执行了什么:

  • 关键点:检查状态:它也会首先检查 htim2.State 是否等于 HAL_TIM_STATE_READY。
  • 冲突发生:因为你先执行了 HAL_TIM_Base_Start,此时 htim2.State 已经是 BUSY 了!
  • 直接返回:HAL_TIM_Base_Start_IT 发现状态不是 READY,它会判定“此句柄正在被占用”,然后直接返回 HAL_ERROR,根本不会去设置使能中断的寄存器。

2、串口DMA发送:如果我开启DMA发送,但是发送一次就不发送了 ,原因是因为未开启串口全局中断。

HAL 库的状态机非常严谨(甚至可以说是死板)。
当你在代码里调用 HAL_UART_Transmit_DMA(&huart1, buffer, len); 时,发生了以下事情:

  1. HAL 库把串口的状态 huart->gState 标记为 HAL_UART_STATE_BUSY_TX (忙碌状态)。
  2. DMA 接管总线,把数据搬运给串口。
  3. 关键点来了:DMA 搬运完最后一个字节后,需要触发一个 DMA 传输完成中断 (DMA TC Interrupt)。
  4. 如果在中断里,HAL 库检测到搬运完了,它才会把串口的状态改回 HAL_UART_STATE_READY (空闲状态)。

问题就在这里:
如果你在 CubeMX 里没有勾选 DMA 的全局中断(NVIC),CPU 就永远不知道 DMA 已经发完了。
结果就是:事情虽然做完了,但状态机永远卡在 BUSY 状态。
当你第二次调用 HAL_UART_Transmit_DMA 时,HAL 库一查状态,“哇,还在忙”,于是直接返回 HAL_BUSY 并拒绝工作。


在应用层编写之前,先搭建程序调试框架,将调试部分完全独立出去,作为不影响主程序的附加部分,使用DMA进行发送,格式化信息后直接加入缓存列表,定时器定时查询列表并打印日志输出,除去内存搬运过程消耗极少CPU时间,全程DMA操作

日志输入输出函数(已测试完备):

int Log_Input(uint8_t log_Type,const char *format, ...)
{
	va_list args;
	uint32_t length = 0;
	uint32_t timeout = 0;
	
	RTC_TimeTypeDef sTime;
	RTC_DateTypeDef sDate;
	HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
	HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
	
	
	switch(log_Type)
	{
		case Syslog: length = sprintf(Log_Message_buffer.Message_text, "[SysLog	:%d,%d-%d-%02d:%02d:%02d]"
			,Q_reman,sDate.Month,sDate.Date, sTime.Hours, sTime.Minutes, sTime.Seconds); break;
		
		case orderlog: length = sprintf(Log_Message_buffer.Message_text, "[taskLog:%d,%d-%d-%02d:%02d:%02d]"
			,Q_reman,sDate.Month,sDate.Date, sTime.Hours, sTime.Minutes, sTime.Seconds); break;
		
		case Debuglog: length = sprintf(Log_Message_buffer.Message_text, "[Debglog:%d,%d-%d-%02d:%02d:%02d]"
			,Q_reman,sDate.Month,sDate.Date, sTime.Hours, sTime.Minutes, sTime.Seconds); break;
		
		default: length = sprintf(Log_Message_buffer.Message_text, "[udeflog:%d,%d-%d-%02d:%02d:%02d]"
			,Q_reman,sDate.Month,sDate.Date, sTime.Hours, sTime.Minutes, sTime.Seconds); break;
	}
	
	va_start(args, format);
    length += vsnprintf((char *)Log_Message_buffer.Message_text+length, Log_Max_len, (char *)format, args);
    va_end(args);
	
	//插入缓存队列区
	Log_Q.busy = 1;//占用队列
	if((Log_Q.rear + 1) % Log_Queue_len == Log_Q.head) //判断缓存是否满
	{
		Log_Q.busy = 0;//释放队列
		LED_RGB_SET_Color(Red);//指示灯变红
		return -1;///
	}
	else
	{
		if(Log_Q.head == -1) 
		{
			Log_Q.head = 0; //是否为空
		}
		
		Log_Message_buffer.Message_lenth = length;
		Log_Q.rear = (Log_Q.rear + 1) % Log_Queue_len;
		memcpy(&Log_Q.Log_Queue[Log_Q.rear],&Log_Message_buffer,sizeof(Log_Message_buffer));
		
		if(Log_Q.rear >= Log_Q.head) {
				Q_reman =  (Log_Q.rear - Log_Q.head);
			} 
		else{
				Q_reman =  (Log_Queue_len - Log_Q.head + Log_Q.rear);
			}	
	}	
	Log_Q.busy = 0;//释放队列
	return log_Type;
}



int Log_output_from_Queue(Log_Message_struct* out_buffer,uint16_t* len)
{
	if (Log_Q.head == -1) 
	{
		LED_RGB_SET_Color(Green);//指示灯变绿
		return -1;//dbg_printf("TASK_Q empty\r\n");
	}
	else
	{
		Log_Q.head %= Log_Queue_len;
		memcpy((uint8_t *)out_buffer,Log_Q.Log_Queue[Log_Q.head],Log_Max_len);
		
		//判断队列是否为空
		if (Log_Q.head == Log_Q.rear) 
		{
			Log_Q.head = -1;
			Log_Q.rear = -1;
			LED_RGB_SET_Color(Green);//指示灯变绿
			return 0;
		} 
		else 	Log_Q.head = (Log_Q.head + 1) % Log_Queue_len;
	}
	LED_RGB_SET_Color(Blue);//指示灯变绿
	return 1;
}


void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == TIM1) // 确认是哪个定时器触发的
    {
		static int i = 0;
		static int count = 0;
		if (CMD_UART.gState == HAL_UART_STATE_READY) {
			i = 0;
			Q_empty_flag = Log_output_from_Queue(&Log_out_buffer,&Log_out_len);
			if(Q_empty_flag != -1)
				HAL_UART_Transmit_DMA(&CMD_UART,(uint8_t *)&Log_out_buffer.Message_text,Log_out_buffer.Message_lenth);
			else return;
		}
    }
}

日志输出具有类型信息、时间信息、以及缓存队列的剩余数量信息、后续可拓展完善

上一页 1 2 3 4 下一页
标签: 暂无
最后更新:2026年10月21日

cuit-tt

这个人很懒,什么都没留下

点赞
< 上一篇

归档

  • 2026 年 9 月
  • 2026 年 5 月
  • 2026 年 4 月
  • 2026 年 3 月
  • 2026 年 1 月
  • 2025 年 12 月
  • 2025 年 11 月
  • 2025 年 10 月
  • 2024 年 3 月

分类

  • 学习记录
  • 未分类
  • 硬件项目
  • 软件项目

COPYRIGHT © 2025 爱坤之家. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

蜀ICP备2025169596号