请教一个stm32f101r8偶然死机的问题
用stm32f101r8一批设备,总是出现不定时死机现象,仅有几台不死机,而且有的死机很频繁,有的不那么频繁,看不出什么规律。
刚开始设计的时候,用了看门狗没发现这个问题,也是很偶然才发现这个问题,虽然用了狗不会死机,但是既然这么多的死机肯定是有问题的。
查了很长时间,没看出问题了,请各位高手帮帮忙。
用扫描的方式ADC采样8路信号 Tim2每0.5ms触发采样一次 dma传输 在Tim2中断中计数20次对采样的数据运算一次。
7路ADC采样端口为
PC0-ADC_IN10
PC1-ADC_IN11
PC2-ADC_IN12
PC3-ADC_IN13
PA0-ADC_IN0
PA1-ADC_IN1
PA2-ADC_IN2
内部参考
程序中去掉了看门狗。
其他ADC的输入通道保持复位时的默认配置时,设备运行正常,几十台设备连续几天没有出现死机现象。
如果PC4-ADC_IN14和PC5_ADC_IN15配置成“推挽输出”时,一小时内有几台出现死机,运行一整天的话,几乎一大半都会死机。
PC4-ADC_IN14和PC5_ADC_IN15配置代码如下:
GPIOC->CRL &= (u32)(~(u32)((0xF<<16)|(0xF<<20)));
GPIOC->CRL |= (u32)((0x1<<16)|(0x1<<20));
如不加上这段代码,不会出现问题,如果加上了这段代码,就会出现问题。
ADC DMA 和 TIM2 的初始化函数,以及tim2中断函数如下。
//ADC初始化
#define ADC ADC1
void AdcInit(void)
{
// PC3-ADC_IN13
// PA0-ADC_IN0
// PA1-ADC_IN1
// PC2-ADC_IN12
// PC1-ADC_IN11
// PC0-ADC_IN10
// PA2-ADC_IN2
GPIOC->CRL &= (u32)(~(u32)((GPIO_MODE<<GPIO_CR_PIN0)|(GPIO_MODE<<GPIO_CR_PIN1)|(GPIO_MODE<<GPIO_CR_PIN2)|(GPIO_MODE<<GPIO_CR_PIN3)));
GPIOC->CRL |= (u32)((GPIO_MODE_AIN<<GPIO_CR_PIN0)|(GPIO_MODE_AIN<<GPIO_CR_PIN1)|(GPIO_MODE_AIN<<GPIO_CR_PIN2)|(GPIO_MODE_AIN<<GPIO_CR_PIN3));
GPIOA->CRL &= (u32)(~(u32)((GPIO_MODE<<GPIO_CR_PIN0)|(GPIO_MODE<<GPIO_CR_PIN1)|(GPIO_MODE<<GPIO_CR_PIN2)));
GPIOA->CRL |= (u32)((GPIO_MODE_AIN<<GPIO_CR_PIN0)|(GPIO_MODE_AIN<<GPIO_CR_PIN1)|(GPIO_MODE_AIN<<GPIO_CR_PIN2));
// 禁用模拟看门狗
// 独立模式
// 禁止间断模式
// 使用扫描模式
// 禁止中断
ADC->CR1 = ADC_CR1_SCAN;
// 启用温度传感器和VREFINT
// 使用外部事件启动转换,
// 右对齐
// DMA模式
ADC->CR2 = ADC_CR2_TSVREFE|ADC_CR2_EXTTRIG|ADC_CR2_EXTSEL_SWSTART|ADC_CR2_DMA|ADC_CR2_ADON;
// 采样28.5个周期
ADC->SMPR1 = ADC_SMPR1_SMP17_55D5|ADC_SMPR1_SMP13_55D5|ADC_SMPR1_SMP12_55D5
|ADC_SMPR1_SMP11_55D5|ADC_SMPR1_SMP10_55D5;
ADC->SMPR2 = ADC_SMPR2_SMP0_55D5|ADC_SMPR2_SMP1_55D5|ADC_SMPR2_SMP2_55D5;
// 总共8个通道
// 调整过顺序,IA和IC换了个顺序
// 顺序是IN2,IN13,IN10,IN0,IN11,IN1,IN12,IN17
ADC->SQR3 = (ADC_SQR3_SQ1_1)
|(ADC_SQR3_SQ2_3|ADC_SQR3_SQ2_2|ADC_SQR3_SQ2_0)
|(ADC_SQR3_SQ3_3|ADC_SQR3_SQ3_1)
|(0)
|(ADC_SQR3_SQ5_3|ADC_SQR3_SQ5_1|ADC_SQR3_SQ5_0)
|(ADC_SQR3_SQ6_0);
ADC->SQR2 = (ADC_SQR2_SQ7_3|ADC_SQR2_SQ7_2)
|(ADC_SQR2_SQ8_4|ADC_SQR2_SQ8_0);
ADC->SQR1 = ADC_SQR1_L_2|ADC_SQR1_L_1|ADC_SQR1_L_0;
// 校准
ADC->CR2 |= ADC_CR2_RSTCAL;
while ((ADC->CR2&ADC_CR2_RSTCAL));
ADC->CR2 |= ADC_CR2_CAL;
while ((ADC->CR2&ADC_CR2_CAL));
}
// DMA初始化
#define DMA DMA1
#define DMA_ADC DMA1_Channel1
void DmaInit(void)
{
DMA_ADC->CCR &= ~DMA_CCR_EN;
// 传输数量
DMA_ADC->CNDTR = 8*20;
// 外设地址
DMA_ADC->CPAR = ADC_DR_ADDRESS;
// 数据存放位置
// 数组g_AdcViLcItemArr[20]
DMA_ADC->CMAR = (u32)g_AdcViLcItemArr;
// 初始化与ADC1相关的DMA
// 使能DMA通道1
// 从外设读
// 存储器宽度和外设宽度为16位
// 外设地址不变,存储器增加
// 优先级最高
DMA_ADC->CCR = DMA_CCR_MSIZE_16BIT|DMA_CCR_PSIZE_16BIT|DMA_CCR_MINC
|(DMA_CCR_PL_0|DMA_CCR_PL_1);
DMA_ADC->CCR |= DMA_CCR_EN;
}
g_AdcViLcItemArr[20]的单元为
typedef struct
{
vu16 k1;//ADC_IN2
vu16 k2;//ADC_IN10
vu16 k3;//ADC_IN1
vu16 k4;//ADC_IN11
vu16 k5;//ADC_IN0
vu16 k6;//ADC_IN12
vu16 k7;//ADC_IN13
vu16 Vref;//内部参考电压ADC_IN17
}AdcViLcItem, *pAdcViLcItem;
//采样tim2设置
#define SMPL_TIM TIM2
void SmplTimInit(void)
{
// 每0.5ms采样一个点
//设定计数器自动重装值
SMPL_TIM->ARR = 1000;
SMPL_TIM->PSC = 13;
//允许更新中断,允许触发中断
SMPL_TIM->DIER |= (u16)(TIM_DIER_UIE|TIM_DIER_TIE);
//使能定时器
SMPL_TIM->CR1 |= (u16)(TIM_CR1_CEN);
NVIC_EnableChannel(SMPL_TIM_IRQn);
NVIC_SetPriority(SMPL_TIM_IRQn, NVIC_PRIOR_SMPL_TIM);
}
// 定时器中断
#define DMA_ADCOK() (DMA->ISR&DMA_ISR_TCIF1)
#define DMA_CLRADCOK() (DMA->IFCR |= DMA_IFCR_CTCIF1)
#define START_ADC_SAMPLE() ADC1->CR2 |= ADC_CR2_SWSTART
void VILC_SmplTimISR(void)
{
static u8 index = 0;
// 先禁止计时器
SMPL_TIM->CR1 &= ~(u16)(TIM_CR1_CEN);
SMPL_TIM->SR &= ~(TIM_SR_UIF|TIM_SR_TIF);//清除中断标志位
index++;
if (20==index)
{
// 运算
// 检测DMA是否完成
if (DMA_ADCOK())
{
DMA_CLRADCOK();
}
DmaInit();
}
if (index>=20)
{
index = 0;
}
// 触发ADC采样
START_ADC_SAMPLE();
// 使能计时器
SMPL_TIM->CR1 |= (u16)(TIM_CR1_CEN);
} |