2017-05-09 7 views
3

STM32L476VG MCU 검색 보드에 병렬로 전송되는 8 비트 값을 읽으려고합니다. 데이터의 비트 7 및 6은 각각 핀 PC15 및 PC14로 보내지 만 비트 6-0은 핀 PE15-PE10에 전송됩니다. 필자는 오실로스코프의 해당 핀에 와이어를 테스트하여 사실상 보드에 신호가 오도록했습니다. 나는 문제의 GPIO 핀이 제대로 입력으로 초기화되는 것을 확신 :STM Discovery 보드에서 입력 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

한 수준 위로 검색하십시오. GPIOx-> IDR 레지스터에 올바른 값이 있습니까? – Jeroen3

답변

-1

RCC 및/또는 MODER 레지스터가 올바르게 적용되었는지 확인하십시오.
RCC 레지스터를 설정 한 후 약간의 시간 지연을 추가하십시오.

어쩌면 당신의 컴파일러는 무엇인가를 최적화하고 다음과 같은 조건이 충족되지 :

When the peripheral clock is not active, the peripheral registers read or write accesses are not supported.
The enable bit has a synchronization mechanism to create a glitch free clock for the peripheral.
After the enable bit is set, there is a 2 clock cycles delay before the clock be active.
Caution:
Just after enabling the clock for a peripheral, software must wait for a delay before accessing the peripheral registers.

편집 :

참고 : 다음은 솔루션 접근 방식과 잘못된 것으로 나타났다. 자세한 내용은 의견보기

난 그냥 위의 init_adc_gpio 기능을 컴파일하고있어 내 컴파일러는 다음과 같은 어셈블러 지침 (-03) 생성 컴파일러는 지시 순서를 볼 수 있듯이

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) 
} 

간단한 NOP 명령을 또한 어떻게해야 등록하는 모더를 설정하기 전에.

참고 : 컴파일러 장벽은 약간 다른 어셈블러 코드로 연결됩니다. 그러나 둘 다 여전히 맞습니다.

+0

각 주변 장치의 활성화 비트를 설정 한 다음 해당 주변 장치를 다시 터치하기 전에 2 개의 다른 수정 - 수정 - 쓰기 작업이 뒤 따르기 때문에 위의 코드에서 적어도 4 개의 (그리고 아마도 더 많은) 클럭 사이클의 암시 적 지연이 있습니다. – berendi

+0

주변 장치 레지스터는 컨트롤러 헤더에서 '휘발성 (volatile)'으로 선언되며, 세계의 컴파일러는 컨트롤러 헤더에 대한 액세스를 최적화하지 않습니다. – berendi

+0

맞습니다. 문제가 아닙니다.그러나 그럼에도 불구하고 나는이 레지스터가 올바르게 설정되어 있는지 확인합니다. 또한 런타임 중에. 그렇지 않으면 다른 것은 잘못 될 수 있습니다. – veeman