2017-05-09 71 views
3

我試圖讀取並行發送到STM32L476VG MCU Discovery板的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功能和我的編譯器生成以下彙編指令(-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] 

正如你所看到的編譯器重新排序的說明。因此寄存器設置不正確。 注意:其實序列是正確的。反彙編程序如何顯示它可能會誤導某人。設置寄存器MODER應該做它之前也

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指令:

爲了解決這個問題,你可以使用一個explicit compiler barrier至極阻止編譯器重新排序的命令。

注:編譯器障礙導致略有不同的彙編代碼。但兩者仍然正確。

+0

上述代碼中至少有4個(也可能更多)時鐘週期存在隱式延遲,因爲在再次觸摸外設之前,爲每個外設設置啓用位之後是2個其他讀取 - 修改 - 寫入操作。 – berendi

+0

外設寄存器在控制器頭文件中聲明爲volatile,世界上沒有編譯器會優化對它們的訪問。 – berendi

+0

你是對的,這不應該是一個問題。但是,我會檢查這些寄存器是否設置正確。在運行期間也是如此。否則沒有別的可能是錯的。 – veeman