Cpu registers 写入CAN_BTR寄存器时STM32F407的奇怪行为
我定义了以下用户类型:Cpu registers 写入CAN_BTR寄存器时STM32F407的奇怪行为,cpu-registers,stm32f4,Cpu Registers,Stm32f4,我定义了以下用户类型: typedef struct { union { struct { uint32_t BRP :10; uint32_t Reserved_1 :6; uint32_t TS1 :4; uint32_t TS2 :3; uint32_t Reserved_2 :1; uint32_t
typedef struct
{
union
{
struct
{
uint32_t BRP :10;
uint32_t Reserved_1 :6;
uint32_t TS1 :4;
uint32_t TS2 :3;
uint32_t Reserved_2 :1;
uint32_t SJW :2;
uint32_t Reserved_3 :4;
uint32_t LBKM :1;
uint32_t SILM :1;
};
uint32_t reg;
};
}__attribute__((packed, aligned(1))) _CAN_BTR;
然后创建变量:
_CAN_BTR *CAN_BTR = (_CAN_BTR*) &(CAN->BTR);
但当使用以下代码编写时,我得到了错误的结果:
CAN_BTR->TS1 = 9;
CAN_BTR->TS2 = 4;
CAN_BTR->BRP = 6;
CAN_BTR->SJW = 3;
最后,注册似乎是一个问题,因为在注册之前一切都很好
strb r3, [r2, #2]
其中,r3保持正确值r2保持CAN#BTR寄存器的基址,并将#2 ossfet点与保持TS1值的寄存器的第三个字节相连
用asm做了一些实验后,我发现出于某种原因
strb r3, [r2, #2]
始终修改该寄存器的第一个(偏移量0)和第三个(偏移量2)字节。对于局部变量,不存在这样的问题
CAN_BTR默认值为0x1230000,并且在以下任何指示之后
strb r3, [r2, #0]
strb r3, [r2, #1]
strb r3, [r2, #2]
strb r3, [r2, #3]
它变成了0x1290129
是否有我不知道的硬件缺陷或限制?我查看了STM32F407的勘误表,但在CAN部分中并没有类似的内容
提前感谢您的回答
*更新
还有关于代码反汇编列表的更多信息:
79 CAN_BTR->TS1 = 9;
080006da: ldr r2, [r7, #16]
080006dc: ldrb r3, [r2, #2]
080006de: movs r1, #9
080006e0: bfi r3, r1, #0, #4
080006e4: strb r3, [r2, #2]
80 CAN_BTR->TS2 = 4;
080006e6: ldr r2, [r7, #16]
080006e8: ldrb r3, [r2, #2]
080006ea: movs r1, #4
080006ec: bfi r3, r1, #4, #3
080006f0: strb r3, [r2, #2]
81 CAN_BTR->BRP = 6;
080006f2: ldr r3, [r7, #16]
080006f4: movs r2, #0
080006f6: orr.w r2, r2, #6
080006fa: strb r2, [r3, #0]
080006fc: ldrb r2, [r3, #1]
080006fe: bic.w r2, r2, #3
08000702: strb r2, [r3, #1]
82 CAN_BTR->SJW = 3;
08000704: ldr r2, [r7, #16]
08000706: ldrb r3, [r2, #3]
08000708: orr.w r3, r3, #3
0800070c: strb r3, [r2, #3]
在第一行之前,寄存器具有默认值0x1230000。
在这条线之后
080006e4: strb r3, [r2, #2]
寄存器值为0x1290129
我还需要展示更多的代码来说明我的问题吗
*更新2
现在类型定义为:
typedef struct
{
union
{
struct
{
uint32_t BRP :10;
uint32_t :6;
uint32_t TS1 :4;
uint32_t TS2 :3;
uint32_t :1;
uint32_t SJW :2;
uint32_t :4;
uint32_t LBKM :1;
uint32_t SILM :1;
};
uint32_t reg;
};
} _CAN_BTR;
但这会导致相同的asm代码:
86 CAN_BTR->TS1 = 9;
08000718: ldr r2, [r7, #16]
0800071a: ldrb r3, [r2, #2]
0800071c: movs r1, #9
0800071e: bfi r3, r1, #0, #4
08000722: strb r3, [r2, #2]
*SOULTION
正如问题所指出的,在访问时可以注册为字节,但参考手册只允许字(32位)访问。谢谢 CAN寄存器可作为字访问。您的代码正在以字节的形式访问它们,这是无效的 不要引入指针,因为它会影响性能
}\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu;对齐毫无意义。打包是不需要的,它会发出非常低效的代码,并且还会强制进行无效的字节访问
您不需要命名位字段填充
typedef struct
{
union
{
struct
{
uint32_t BRP :10;
uint32_t :6;
uint32_t TS1 :4;
uint32_t TS2 :3;
uint32_t :1;
uint32_t SJW :2;
uint32_t :4;
uint32_t LBKM :1;
uint32_t SILM :1;
};
uint32_t reg;
};
}_CAN_BTR;
并在不引入任何开销的情况下访问位字段
MYCAN_BTR -> SJW = ....
更新如果编译器生成此代码,则需要以不同的方式执行
#define MODIFY_CAN_BTR(field,val) do{_CAN_BTR btr = CAN->BTR; btr -> field = val; CAN -> BTR = btr -> reg;}while(0)
见我修正后的答案。你的包装和校准是错误的。删除它,它将正常工作#定义MYCAN_BTR((volatile _CAN_BTR*)(&CAN->BTR))
和MYCAN_BTR->TS1=9
produses same:CAN->BTR=0x1290129
@Erlewar是否删除了该属性?是的,我更新了问题。@Erlewar查看我的修订答案看起来编译器甚至会对未打包的结构使用字节访问,直到变量不易失为止。使其易失性后,它使用str
而不是strb
,修改也没有问题。
#define MODIFY_CAN_BTR(field,val) do{_CAN_BTR btr = CAN->BTR; btr -> field = val; CAN -> BTR = btr -> reg;}while(0)