我正在尝试读取与STM32L476VG MCU发现板并行发送的8位值。数据的第7位和第6位分别被发送到引脚PC15和PC14,而位6-0被发送到引脚PE15-PE10。我测试了示波器上那些引脚的电线,以确保实际上有一个信号进入电路板。我很确定所讨论的GPIO引脚已正确初始化为输入:
void init_adc_gpio (void) {
RCC->AHB2ENR |= RCC_AHB2ENR_GPIOCEN; // Enable clock for GPIOC
RCC->AHB2ENR |= RCC_AHB2ENR_GPIOEEN; // GPIOE
RCC->AHB2ENR |= RCC_AHB2ENR_GPIOHEN; // GPIOH
GPIOC->MODER &= (uint32_t)0x0FFFFFFFU; // Pins 14-15 of C -> input (2 most significant bits of ADC data)
GPIOE->MODER &= (uint32_t)0x000FFFFFU; // Pins 10-15 of E -> input (6 least significant bits of ADC data)
GPIOH->MODER &= (uint32_t)0xFFFFFFFCU; // Pin 0 of H -> input (ADC data ready flag)
}
我正在尝试使用此函数读取8位数据,只要设置了一个标志(表示ADC中的数据已准备好处理),就会调用该函数:
uint8_t read_adc_data (void) {
uint8_t adc_data;
adc_data = ((GPIOC->IDR & (uint32_t)0x0000C000U) >> 8);
adc_data |= ((GPIOE->IDR & (uint32_t)0x0000FC00U) >> 10);
return adc_data;
}
但是,根据调试,adc_data由于某种原因总是为0。即使将其更改为此也不起作用:
uint8_t read_adc_data (void) {
uint8_t adc_data;
adc_data = (GPIOC->IDR >> 8) | (GPIOE->IDR >> 10);
return adc_data;
}
我觉得这里有一些非常明显的东西,但我的教授和他的助手们也无法弄明白。
答案 0 :(得分:-1)
检查RCC和/或MODER寄存器是否正确应用 设置RCC寄存器后尝试添加一些延迟。
也许您的编译器会优化某些内容并且不满足以下条件:
当外设时钟未激活时,不支持外设寄存器的读或写访问 使能位具有同步机制,可为外设创建无干扰时钟 使能位置1后,在时钟有效之前有2个时钟周期的延迟 的注意:强>
在为外设启用时钟之后,软件必须等待延迟才能访问外设寄存器。
修改强>
注意:以下是一种解决方案,似乎是错误的。 有关详细信息,请参阅注释。
我刚刚编译了上面的 init_adc_gpio 函数,我的编译器会生成以下汇编程序指令(-O3):
RCC->AHB2ENR |= RCC_AHB2ENR_GPIOCEN; // Enable clock for GPIOC
0x080004d0 ldr r3, [pc, 60] ; (0x8000510 <init_adc_gpio+64>)
GPIOE->MODER &= (uint32_t)0x000FFFFFU; // Pins 10-15 of E -> input (6 least significant bits of ADC data)
0x080004d2 ldr r0, [pc, 64] ; (0x8000514 <init_adc_gpio+68>)
0x080004d4 ldr r2, [r3, 76] ; 0x4c
GPIOH->MODER &= (uint32_t)0xFFFFFFFCU; // Pin 0 of H -> input (ADC data ready flag)
0x080004d6 ldr r1, [pc, 64] ; (0x8000518 <init_adc_gpio+72>)
0x080004d8 orr.w r2, r2, 4
void init_adc_gpio(void) {
0x080004dc push {r4}
0x080004de str r2, [r3, 76] ; 0x4c
RCC->AHB2ENR |= RCC_AHB2ENR_GPIOEEN; // GPIOE
0x080004e0 ldr r2, [r3, 76] ; 0x4c
GPIOC->MODER &= (uint32_t)0x0FFFFFFFU; // Pins 14-15 of C -> input (2 most significant bits of ADC data)
0x080004e2 ldr r4, [pc, 56] ; (0x800051c <init_adc_gpio+76>)
0x080004e4 orr.w r2, r2, 16
0x080004e8 str r2, [r3, 76] ; 0x4c
RCC->AHB2ENR |= RCC_AHB2ENR_GPIOHEN; // GPIOH
0x080004ea ldr r2, [r3, 76] ; 0x4c
0x080004ec orr.w r2, r2, 128 ; 0x80
0x080004f0 str r2, [r3, 76] ; 0x4c
0x080004f2 ldr r3, [r4, 0]
0x080004f4 bic.w r3, r3, 4026531840 ; 0xf0000000
0x080004f8 str r3, [r4, 0]
0x080004fa ldr r3, [r0, 0]
}
0x080004fc ldr.w r4, [sp], 4
0x08000500 ubfx r3, r3, 0, 20
0x08000504 str r3, [r0, 0]
0x08000506 ldr r3, [r1, 0]
0x08000508 bic.w r3, r3, 3
0x0800050c str r3, [r1, 0]
0x0800050e bx lr
0x08000510 .word 0x40021000 ; [RCC]
0x08000514 .word 0x48001000 ; [GPIOE]
0x08000518 .word 0x48001c00 ; [GPIOH]
0x0800051c .word 0x48000800 ; [GPIOC]
如您所见,编译器对指令重新排序。因此寄存器设置不正确。 注意:实际上序列是正确的。反汇编程序如何显示它可能会误导某人。
要解决此问题,您可以使用explicit compiler barrier阻止编译器对命令重新排序:
void init_adc_gpio(void) {
RCC->AHB2ENR |= RCC_AHB2ENR_GPIOCEN; // Enable clock for GPIOC
RCC->AHB2ENR |= RCC_AHB2ENR_GPIOEEN; // GPIOE
RCC->AHB2ENR |= RCC_AHB2ENR_GPIOHEN; // GPIOH
asm("" ::: "memory"); // prevent instruction reordering
GPIOC->MODER &= (uint32_t)0x0FFFFFFFU; // Pins 14-15 of C -> input (2 most significant bits of ADC data)
GPIOE->MODER &= (uint32_t)0x000FFFFFU; // Pins 10-15 of E -> input (6 least significant bits of ADC data)
GPIOH->MODER &= (uint32_t)0xFFFFFFFCU; // Pin 0 of H -> input (ADC data ready flag)
}
设置MODER寄存器之前的简单nop指令也应该这样做。
注意:编译器障碍会导致汇编代码略有不同。但两者仍然正确。