/*!
* [url=home.php?mod=space&uid=288409]@file[/url] main.c
*
* [url=home.php?mod=space&uid=247401]@brief[/url] Main program body
*
* [url=home.php?mod=space&uid=895143]@version[/url] V1.0.3
*
* [url=home.php?mod=space&uid=212281]@date[/url] 2023-07-31
*
* @attention
*
* Copyright (C) 2021-2023 Geehy Semiconductor
*
* You may not use this file except in compliance with the
* GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
*
* The program is only for reference, which is distributed in the hope
* that it will be useful and instructional for customers to develop
* their software. Unless required by applicable law or agreed to in
* writing, the program is distributed on an "AS IS" BASIS, WITHOUT
* ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
* See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
* and limitations under the License.
*/
/* Includes */
#include "main.h"
#include "Board.h"
#include "apm32f4xx_gpio.h"
#include "apm32f4xx_adc.h"
#include "apm32f4xx_misc.h"
#include "apm32f4xx_usart.h"
#include "apm32f4xx_tmr.h"
#include <stdio.h>
#include <string.h>
/** @addtogroup Examples
@{
*/
/** @addtogroup ADC_AnalogWindowWatchdog
@{
*/
/** @defgroup ADC_AnalogWindowWatchdog_Macros Macros
@{
*/
/* printf using USART1 */
#define DEBUG_USART USART1
#define APM_COMInit APM_TINY_COMInit
/**@} end of group ADC_AnalogWindowWatchdog_Macros*/
/** @defgroup ADC_AnalogWindowWatchdog_Functions Functions
@{
*/
// 用户模式堆栈配置
#define PSP_STACK_SIZE 512
static uint32_t psp_stack[PSP_STACK_SIZE/4] __attribute__((aligned(8)));
void USARTInit(void);
void generate_BusFault(void);
void generate_UsageFault(void);
void generate_HardFault(void);
void print_fault_status(void);
// MPU配置(触发保护错误)
void MPU_Config(void)
{
// 关闭MPU
ARM_MPU_Disable();
/* 配置区域0:全地址空间禁止访问 */
ARM_MPU_SetRegion(
ARM_MPU_RBAR(0, 0x00000000), // 区域编号0,基地址0x00000000
ARM_MPU_RASR(
1, // DisableExec:禁止指令获取
ARM_MPU_AP_NONE, // 无访问权限
0, // TypeExtField:设备内存
0, // IsShareable:非共享
0, // IsCacheable:不可缓存
0, // IsBufferable:不可缓冲
0x00, // SubRegionDisable:不禁止任何子区域
ARM_MPU_REGION_SIZE_4GB // 覆盖整个4GB地址空间
)
);
// 启用MPU并允许特权模式默认内存映射
ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk);
// 确保配置生效
__DSB();
__ISB();
}
// 硬错误诊断处理
__attribute__((naked)) void HardFault_Handler(void)
{
__asm volatile (
"TST LR, #4\n" // 检查EXC_RETURN的位2
"ITE EQ\n" // 根据结果选择堆栈指针
"MRSEQ R0, MSP\n" // 使用MSP
"MRSNE R0, PSP\n" // 使用PSP
"B HardFault_Diagnose\n"
);
}
void HardFault_Diagnose(uint32_t *stackFrame)
{
volatile uint32_t cfsr = SCB->CFSR;
volatile uint32_t hfsr = SCB->HFSR;
volatile uint32_t bfar = SCB->BFAR;
printf("\n!!! HardFault Occurred !!!\n");
printf("CFSR: 0x%08X\n", cfsr);
printf("HFSR: 0x%08X\n", hfsr);
if(cfsr & (1 << 16)) { // 检查BFARVALID标志
printf("BFAR: 0x%08X\n", bfar);
}
printf("Stack Frame:\n");
printf("R0 : 0x%08X\n", stackFrame[0]);
printf("R1 : 0x%08X\n", stackFrame[1]);
printf("R2 : 0x%08X\n", stackFrame[2]);
printf("R3 : 0x%08X\n", stackFrame[3]);
printf("R12: 0x%08X\n", stackFrame[4]);
printf("LR : 0x%08X\n", stackFrame[5]);
printf("PC : 0x%08X\n", stackFrame[6]);
printf("xPSR:0x%08X\n", stackFrame[7]);
while(1); // 进入死循环便于调试
}
// 用户模式任务(故意触发错误)
__attribute__((noreturn)) void User_Task(void)
{
printf("\n[User Task] Entering User Mode\n");
printf("Current CONTROL: 0x%08X\n", __get_CONTROL());
// 尝试非法操作(以下三种错误任选其一)
// 1. 访问特权寄存器
SCB->SHCSR = 0; // 触发UsageFault
// 2. 访问受保护内存
// uint32_t *ptr = (uint32_t*)0x20000000; // 受MPU保护区域
// *ptr = 0xDEADBEEF; // 触发MemManage
// 3. 非法地址访问
// uint32_t *bad_ptr = (uint32_t*)0xE0000000; // 保留地址
// *bad_ptr = 0xCAFEBABE; // 触发BusFault
while(1);
}
/*!
* [url=home.php?mod=space&uid=247401]@brief[/url] Main program
*
* @param None
*
* @retval None
*/
int main(void)
{
// 系统初始化
USARTInit();
printf("\nSystem Startup\n");
// 配置MPU
MPU_Config();
// 初始化PSP堆栈
__set_PSP((uint32_t)(psp_stack + PSP_STACK_SIZE/4 - 1));
memset(psp_stack, 0xAA, PSP_STACK_SIZE); // 填充测试模式
// 切换到用户模式
printf("Switching to User Mode...\n");
__set_CONTROL(0x01); // 启用PSP
__ISB(); // 指令同步屏障
// 跳转到用户任务
User_Task();
// 理论上不会执行到这里
while(1);
}
/*!
* [url=home.php?mod=space&uid=247401]@brief[/url] USART Init
*
* @param None
*
* @retval None
*/
void USARTInit(void)
{
/* USART Initialization */
USART_Config_T usartConfigStruct;
/* USART configuration */
USART_ConfigStructInit(&usartConfigStruct);
usartConfigStruct.baudRate = 115200;
usartConfigStruct.mode = USART_MODE_TX_RX;
usartConfigStruct.parity = USART_PARITY_NONE;
usartConfigStruct.stopBits = USART_STOP_BIT_1;
usartConfigStruct.wordLength = USART_WORD_LEN_8B;
usartConfigStruct.hardwareFlow = USART_HARDWARE_FLOW_NONE;
/* COM1 init*/
APM_COMInit(COM1, &usartConfigStruct);
}
#if defined (__CC_ARM) || defined (__ICCARM__) || (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))
/*!
* [url=home.php?mod=space&uid=247401]@brief[/url] Redirect C Library function printf to serial port.
* After Redirection, you can use printf function.
*
* @param ch: The characters that need to be send.
*
* @param *f: pointer to a FILE that can recording all information
* needed to control a stream
*
* @retval The characters that need to be send.
*
* @note
*/
int fputc(int ch, FILE* f)
{
/* send a byte of data to the serial port */
USART_TxData(DEBUG_USART, (uint8_t)ch);
/* wait for the data to be send */
while (USART_ReadStatusFlag(DEBUG_USART, USART_FLAG_TXBE) == RESET);
return (ch);
}
#elif defined (__GNUC__)
/*!
* [url=home.php?mod=space&uid=247401]@brief[/url] Redirect C Library function printf to serial port.
* After Redirection, you can use printf function.
*
* @param ch: The characters that need to be send.
*
* @retval The characters that need to be send.
*
* @note
*/
int __io_putchar(int ch)
{
/* send a byte of data to the serial port */
USART_TxData(DEBUG_USART, ch);
/* wait for the data to be send */
while (USART_ReadStatusFlag(DEBUG_USART, USART_FLAG_TXBE) == RESET);
return ch;
}
/*!
* [url=home.php?mod=space&uid=247401]@brief[/url] Redirect C Library function printf to serial port.
* After Redirection, you can use printf function.
*
* @param file: Meaningless in this function.
*
* @param *ptr: Buffer pointer for data to be sent.
*
* @param len: Length of data to be sent.
*
* @retval The characters that need to be send.
*
* @note
*/
int _write(int file, char* ptr, int len)
{
int i;
for (i = 0; i < len; i++)
{
__io_putchar(*ptr++);
}
return len;
}
#else
#warning Not supported compiler type
#endif
/**@} end of group ADC_AnalogWindowWatchdog_Functions */
/**@} end of group ADC_AnalogWindowWatchdog */
/**@} end of group Examples */
示例代码中重要的逻辑节点可总结如下: