【STM32】CortexM0单片机中的非对齐访问造成的HardFault

1、问题引入和结论

在CortexM0单片机中,在使用指针进行内存访问的时候需要特别留意访问地址的合法性问题,否则稍有不慎就会进入HardFault,痛苦不堪。

这里先将结论抛出来:

1、u8类型的指针,读写任何地址均是合法的,不会进入HardFault
2、u16类型的指针,读写地址必须是2的倍数,否则会进入HardFault
3、u32类型的指针,读写地址必须是4的倍数,否则会进入HardFault

我们针对以上三个结论分别做测试。
PS:本试验涉及到结构体的字节对齐知识点,如果有疑惑的地方可以查看:结构体的字节对齐规则

2、测试平台

CortexM0 32位单片机

3、u8指针读写内存测试

首先是u8类型指针的测试,以下是测试代码,实际测试时,可以发现代码可以顺利跑下来,而不会进入HardFault。

#pragma pack(4)		//指定对齐是4字节
typedef struct
{
	u8 len;			//自身对齐是1,指定对齐是4,因此有效对齐是1, 0地址存放len
	u8 data[12];	//自身对齐是1,指定对齐是4,因此有效对齐是1, 1地址存放data[0],2地址存放data[1]...
}TEST;
#pragma pack()

TEST test;

u8  *p8;
u16 *p16;
u32 *p32;
volatile u32 temp;

void align_test_p8(void)
{
	p8  = (u8  *)&test.data[0];	//根据结构体字节对齐的规则,test.data[0]的地址肯定是奇数,因为编译器分配的test内存的时候,test的起始地址肯定是4字节对齐的,而len占用1字节,因此data[0]的地址肯定是奇数
		
	temp = p8[0];//访问非对齐地址
	temp = p8[1];//访问2字节对齐的地址
	temp = p8[2];//访问非对齐地址
	temp = p8[3];//访问4字节对齐地址
}
4、u16指针读写内存测试

接下来是u16类型指针的测试,以下是测试代码。

void align_test_p16(void)
{
	p16  = (u16 *)&test.data[0];	//根据结构体字节对齐的规则,test.data[0]的地址肯定是奇数,因为编译器分配的test内存的时候,test的起始地址肯定是4字节对齐的,而len占用1字节,因此data[0]的地址肯定是奇数
	temp = p16[0];//访问非2字节对齐的地址,肯定会进入HardFault
		
	p16  = (u16 *)&test.data[1];	//根据结构体字节对齐的规则,test.data[1]的地址肯定是2的倍数
	temp = p16[0];//访问2字节对齐地址,不会进入HardFault
		
	p16  = (u16 *)&test.data[2];	//根据结构体字节对齐的规则,test.data[2]的地址肯定不是2的倍数
	temp = p16[0];//访问非2字节对齐地址,会进入HardFault
		
	p16  = (u16 *)&test.data[3];	//根据结构体字节对齐的规则,test.data[3]的地址肯定是2的倍数
	temp = p16[0];//访问2字节对齐地址,不会进入HardFault
}

会进入HardFault的情况
在这里插入图片描述
在这里插入图片描述
不会进入HardFault的情况
在这里插入图片描述

5、u32指针读写内存测试

最后是u32类型指针的测试,以下是测试代码,实际调试的时候,程序在跑到断点处后,就会进入HardFault。

void align_test_p32(void)
{
	p32  = (u32 *)&test.data[0];	//根据结构体字节对齐的规则,test.data[0]的地址肯定是奇数,因为编译器分配的test内存的时候,test的起始地址肯定是4字节对齐的,而len占用1字节,因此data[0]的地址肯定是奇数
	temp = p32[0];//访问非4字节对齐的地址,进入HardFault
		
	p32  = (u32 *)&test.data[1];	//根据结构体字节对齐的规则,test.data[1]的地址肯定是2的倍数,但是不是4的倍数
	temp = p32[0];//访问2字节对齐地址,但不是4字节对齐地址,会进入HardFault
		
	p32  = (u32 *)&test.data[2];	//根据结构体字节对齐的规则,test.data[2]的地址肯定不是2的倍数
	temp = p32[0];//访问非4字节对齐地址,进入HardFault
		
	p32  = (u32 *)&test.data[3];	//根据结构体字节对齐的规则,test.data[3]的地址肯定是2的倍数,是4的倍数
	temp = p32[0];//访问4字节对齐地址,不进入HardFault
}

会进入HardFault的情况
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
不会进入HardFault的情况
在这里插入图片描述

6、结论

在CortexM0单片机中,在使用指针进行内存访问的时候需要特别留意访问地址的合法性问题,否则稍有不慎就会进入HardFault。

1、u8类型的指针,读写任何地址均是合法的,不会进入HardFault
2、u16类型的指针,读写地址必须是2的倍数,否则会进入HardFault
3、u32类型的指针,读写地址必须是4的倍数,否则会进入HardFault

  • 10
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值