2017-05-09 3 views
3

J'essaie de lire une valeur de 8 bits envoyée en parallèle à une carte de découverte MCU STM32L476VG. Les bits 7 et 6 des données sont respectivement envoyés aux broches PC15 et PC14, tandis que les bits 6-0 sont envoyés aux broches PE15-PE10. J'ai testé les fils à ces broches sur un oscilloscope pour garantir qu'il y a effectivement un signal venant à la carte. Je suis assez sûr que les broches GPIO en cause sont initialisés comme entrées:Lecture de l'entrée GPIO sur la carte de découverte STM

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

Je suis en train de lire les données 8 bits en utilisant cette fonction, qui est appelée à chaque fois un indicateur est défini (ce qui indique que les données de l'ADC est prêt à traiter):

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

Cependant, selon le débogage, adc_data est toujours 0 pour une raison quelconque. Même changer à ce qui n'a pas fonctionné:

uint8_t read_adc_data (void) { 
    uint8_t adc_data; 
    adc_data = (GPIOC->IDR >> 8) | (GPIOE->IDR >> 10); 
    return adc_data; 
} 

Je me sens comme il y a quelque chose ridiculement évident que je suis absent ici, mais mon professeur et ses assistants ne pouvaient pas comprendre non plus.

+1

Rechercher un niveau supérieur. Les registres GPIOx-> IDR contiennent-ils les valeurs correctes? – Jeroen3

Répondre

-1

Vérifiez si les registres RCC et/ou MODER sont appliqués correctement.
Essayez d'ajouter un peu de retard après avoir réglé le registre RCC.

Peut-être que votre compilateur optimise quelque chose et la condition suivante est pas remplie:

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.

Edit:

Note: Ce qui suit est une approche de solution et semble se tromper. Voir les commentaires pour plus de détails.

Je suis juste compilé la fonction init_adc_gpio ci-dessus et mon compilateur génère les instructions assembleur suivantes (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] 

Comme vous pouvez le voir le compilateur réordonner les instructions. Par conséquent, les registres ne sont pas correctement définis. Remarque: En fait, la séquence est correcte. La façon dont le désassembleur le montre peut induire quelqu'un en erreur.

Pour résoudre ce problème, vous pouvez utiliser un explicit compiler barrier Wich empêche le compilateur de réorganiser les commandes:

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

A NOP simples avant de l'MODER registres devrait le faire aussi.

Remarque: La barrière du compilateur conduit à un code assembleur légèrement différent. Mais les deux sont toujours corrects.

+0

Il y a un retard implicite d'au moins 4 (et probablement beaucoup plus) cycles d'horloge dans le code ci-dessus, car le réglage du bit d'activation pour chaque périphérique est suivi par 2 autres opérations de lecture-modification-écriture avant de toucher à nouveau ce périphérique. – berendi

+0

Les registres périphériques sont déclarés comme «volatile» dans les en-têtes du contrôleur, aucun compilateur dans le monde ne permettrait d'optimiser les accès à ceux-ci. – berendi

+0

Vous avez raison, cela ne devrait pas poser de problème.Mais néanmoins, je vérifierais si ces registres sont réglés correctement. Aussi pendant l'exécution. Sinon, rien d'autre ne peut être faux. – veeman