Cortex-M3 / M4硬故障处理程序
https://blog.frankvh.com/2011/12/07/cortex-m3-m4-hard-fault-handler/
第5章 任务切换设计
http://blog.sina.com.cn/s/blog_98ee3a930102v7zv.html
STM32常见Hard+Fault的诊断
https://wenku.baidu.com/view/3c1146ddd5bbfd0a795673f3.html
__ASM void HardFault_Handler(void)
{
TST lr, #4 // Test for MSP or PSP 测试EXC_RETURN的比特2
ITE EQ //如果为0,
MRSEQ r0, MSP //则使用的是主堆栈,故把MSP的值取出
MRSNE r0, PSP //否则, 使用的是进程堆栈,故把MSP的值取出
IMPORT HardFault_Handler_C //从栈中读取PC的值
B HardFault_Handler_C //从SVC指令中读取立即数放到R0
}
//HardFault_Handler
void HardFault_Handler_C (unsigned int * hardfault_args)
{
unsigned int stacked_r0;
unsigned int stacked_r1;
unsigned int stacked_r2;
unsigned int stacked_r3;
unsigned int stacked_r12;
unsigned int stacked_lr;
unsigned int stacked_pc;
unsigned int stacked_psr;
stacked_r0 = ((unsigned long) hardfault_args[0]);
stacked_r1 = ((unsigned long) hardfault_args[1]);
stacked_r2 = ((unsigned long) hardfault_args[2]);
stacked_r3 = ((unsigned long) hardfault_args[3]);
stacked_r12 = ((unsigned long) hardfault_args[4]);
stacked_lr = ((unsigned long) hardfault_args[5]);
stacked_pc = ((unsigned long) hardfault_args[6]);
stacked_psr = ((unsigned long) hardfault_args[7]);
printf ("\n\n[Hard fault handler - all numbers in hex]\r\n");
printf ("R0 = 0x%08X\r\n", stacked_r0);
printf ("R1 = 0x%08X\r\n", stacked_r1);
printf ("R2 = 0x%08X\r\n", stacked_r2);
printf ("R3 = 0x%08X\r\n", stacked_r3);
printf ("R12 = 0x%08X\r\n", stacked_r12);
printf ("LR [R14] = 0x%08X subroutine call return address\r\n", stacked_lr);
printf ("PC [R15] = 0x%08X program counter\r\n", stacked_pc);
printf ("PSR = 0x%08X\r\n", stacked_psr);
printf ("BFAR = 0x%X\r\n", (*((volatile unsigned long *)(0xE000ED38))));
printf ("CFSR = 0x%X\r\n", (*((volatile unsigned long *)(0xE000ED28))));
printf ("HFSR = 0x%X\r\n", (*((volatile unsigned long *)(0xE000ED2C))));
printf ("DFSR = 0x%X\r\n", (*((volatile unsigned long *)(0xE000ED30))));
printf ("AFSR = 0x%X\r\n", (*((volatile unsigned long *)(0xE000ED3C))));
printf ("SCB_SHCSR = %X\r\n", SCB->SHCSR);
while (1);
}
10min滑动平均滤波算法
long i32VrmsSum;//电压
int i16Vrms;//电压
long i32CtIrms,i32CtIsum;//电流
s16 After_filter[2][100];
u8 L1Voltage10minIndex,L2Voltage10minIndex,L3Voltage10minIndex;
u16 L1Voltage10minSumBuf[10] = {2350,2350,2350,2350,2350,2350,2350,2350,2350,2350},L2Voltage10minSumBuf[10],L3Voltage10minSumBuf[10];
long L1Voltage10minSum = 23500,L2Voltage10minSum,L3Voltage10minSum;
long L1Voltage10minAvg = 2350,L2Voltage10minAvg,L3Voltage10minAvg;
u8 L1Voltage1minIndex,L2Voltage1minIndex,L3Voltage1minIndex;
u16 L1Voltage1minSumBuf[20] = {2350,2350,2350,2350,2350,2350,2350,2350,2350,2350,2350,2350,2350,2350,2350,2350,2350,2350,2350,2350},L2Voltage1minSumBuf[20],L3Voltage1minSumBuf[20];
long L1Voltage1minSum = 47000,L2Voltage1minSum,L3Voltage1minSum;
long L1Voltage1minAvg = 2350,L2Voltage1minAvg,L3Voltage1minAvg;
void OVAV_10min_average(void)
{
static u8 w3sTimerCnt = 0,w10minTimerCnt;
if(++w3sTimerCnt >= 120)//3s
{
w3sTimerCnt = 0;
if(L1Voltage1minIndex >= 20)
{
L1Voltage1minIndex = 0;
}
L1Voltage1minSum = L1Voltage1minSum - L1Voltage1minSumBuf[L1Voltage1minIndex];
L1Voltage1minSumBuf[L1Voltage1minIndex] = Hold_Data_HoldingBuf->VoltageL1;
L1Voltage1minSum += L1Voltage1minSumBuf[L1Voltage1minIndex];
L1Voltage1minIndex++;
L1Voltage1minAvg = L1Voltage1minSum/20;//1min avg
if(++w10minTimerCnt > 20)//60s
{
w10minTimerCnt = 0;
if(L1Voltage10minIndex >= 10)
{
L1Voltage10minIndex = 0;
}
L1Voltage10minSum = L1Voltage10minSum - L1Voltage10minSumBuf[L1Voltage10minIndex];
L1Voltage10minSumBuf[L1Voltage10minIndex] = L1Voltage1minAvg;
L1Voltage10minSum = L1Voltage10minSum + L1Voltage10minSumBuf[L1Voltage10minIndex];
L1Voltage10minIndex++;
L1Voltage10minAvg = L1Voltage10minSum/10;
Hold_Data_HoldingBuf->OVAV_L1 = L1Voltage10minAvg;
}
}
}
void filter(void)
{
u8 count,i;
i32CtIsum = 0;
i32VrmsSum = 0;
for(i = 0;i < 2;i++)
{
for (count = 0; count < 100; count++)
{
After_filter[i][count] = (s16)ADC_RCVTab[2 * count + i] - 2048;
}
}
for (i = 0; i < 100; i++)
{
i32CtIsum += After_filter[0][i] * After_filter[0][i];
//*! 2018-11-01 18:25:53 计算有效值
i32VrmsSum += After_filter[1][i] * After_filter[1][i];
}
}
STM32之汇编操作
常用的指令说明。
指令名称 | 作用 |
EQU | 给数字常量取一个符号名,相当于 C 语言中的 define |
AREA | 汇编一个新的代码段或者数据段 |
SPACE | 分配内存空间 |
PRESERVE8 | 当前文件栈需按照 8 字节对齐 |
EXPORT | 声明一个标号具有全局属性,可被外部的文件使用 |
DCD | 以字为单位分配内存,要求 4 字节对齐,并要求初始化这些内存 |
PROC | 定义子程序,与 ENDP 成对使用,表示子程序结束 |
WEAK | 弱定义,如果外部文件声明了一个标号,则优先使用外部文件定义的标号,如果外部文件没有定义也不出错。要注意的是:这个不是 ARM 的指令,是编译器的,这里放在一起只是为了方便。 |
IMPORT | 声明标号来自外部文件,跟 C 语言中的 EXTERN 关键字类似 |
B | 跳转到一个标号 |
ALIGN | 编译器对指令或者数据的存放地址进行对齐,一般需要跟一个立即 数,缺省表示 4 字节对齐。要注意的是:这个不是 ARM 的指令,是 编译器的,这里放在一起只是为了方便。 |
END | 到达文件的末尾,文件结束 |
IF,ELSE,ENDIF | 汇编条件分支语句,跟 C 语言的 if else 类似 |
MRS | 加载特殊功能寄存器的值到通用寄存器 |
MSR | 存储通用寄存器的值到特殊功能寄存器 |
CBZ | 比较,如果结果为 0 就转移 |
CBNZ | 比较,如果结果非 0 就转移 |
LDR | 从存储器中加载字到一个寄存器中 |
LDR[伪指令] | 加载一个立即数或者一个地址值到一个寄存器。 举例: LDR Rd, = label, 如果 label 是立即数,那 Rd 等于立即数, 如果 label 是一个标识符,比如 指针,那存到 Rd 的就是 label 这个标识符的地址 |
LDRH | 从存储器中加载半字到一个寄存器中 |
LDRB | 从存储器中加载字节到一个寄存器中 |
STR | 把一个寄存器按字存储到存储器中 |
STRH | 把一个寄存器存器的低半字存储到存储器中 |
STRB | 把一个寄存器的低字节存储到存储器中 |
LDMIA | 加载多个字,并且在加载后自增基址寄存器 |
STMIA | 存储多个字,并且在存储后自增基址寄存器 |
LDMFD | |
ORR | 按位或 |
BX | 直接跳转到由寄存器给定的地址 |
BL | 跳转到 标号对应的地址,并且把跳转前的下条指令地址保存到 LR |
BLX | 跳转到由寄存器 REG 给出的的地址,并根据 REG 的 LSB 切换处理器状 态 , 还 要 把 转 移 前 的 下 条 指 令 地 址 保 存 到 LR 。 ARM(LSB=0) , Thumb(LSB=1)。 CM3 只在 Thumb 中运行,就必须保证 reg 的 LSB=1,否则一个 fault 打过来 |