在STM Discovery板上读取输入GPIO

时间:2017-05-09 04:56:25

标签: c input stm32 gpio

我正在尝试读取与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;
}

我觉得这里有一些非常明显的东西,但我的教授和他的助手们也无法弄明白。

1 个答案:

答案 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指令也应该这样做。

注意:编译器障碍会导致汇编代码略有不同。但两者仍然正确。