2017-02-07 3 views
4

Je suis en train de développer un noyau de test pour les périphériques Raspberry Pi. Pour ce faire, je dois configurer l'UART afin que nous puissions écrire des données sur l'appareil et pouvoir récupérer les données qui doivent être traitées par le noyau. Je veux que le noyau de test puisse fonctionner sur plusieurs périphériques Raspberry Pi. Il existe cependant un léger problème:Comment déterminer la version de la carte Rasberry Pi en utilisant Arm Assembly/C?

Les adresses UART Diffèrent entre les versions. Par exemple, l'adresse de l'IPD 1 ligne UART GPIO est:

0x20200000 

Mais l'adresse de l'UART GPIO sur les lignes RPi 2 et RPi 3 est:

0x3F200000 

Bien sûr, cela signifie qu'il y Il faudrait deux fonctions UART_INIT distinctes: 1 pour les périphériques RPi 1 et 1 pour RPi 2 et au-delà.

Voici un exemple de code de manipulation UART. Ce code est modifié à partir du code fourni par osdev:

void uart_init_rpi1() 
{ 
    // Disable UART0. 
    mmio_write(PD_UART_INTERNAL_VALUES_RPI1->UART0_CR, 0x00000000); 
    // Setup the GPIO pin 14 && 15. 

    // Disable pull up/down for all GPIO pins & delay for 150 cycles. 
    mmio_write(PD_GPPUD_RPI1, 0x00000000); 
    delay(150); 

    // Disable pull up/down for pin 14,15 & delay for 150 cycles. 
    mmio_write(PD_GPPUDCLK0_RPI1, (1 << 14) | (1 << 15)); 
    delay(150); 

    // Write 0 to GPPUDCLK0 to make it take effect. 
    mmio_write(PD_GPPUDCLK0_RPI1, 0x00000000); 

    // Clear pending interrupts. 
    mmio_write(PD_UART_INTERNAL_VALUES_RPI1->UART0_ICR, 0x7FF); 

    // Set integer & fractional part of baud rate. 
    // Divider = UART_CLOCK/(16 * Baud) 
    // Fraction part register = (Fractional part * 64) + 0.5 
    // UART_CLOCK = 3000000; Baud = 115200. 

    // Divider = 3000000/(16 * 115200) = 1.627 = ~1. 
    // Fractional part register = (.627 * 64) + 0.5 = 40.6 = ~40. 
    mmio_write(PD_UART_INTERNAL_VALUES_RPI1->UART0_IBRD, 1); 
    mmio_write(PD_UART_INTERNAL_VALUES_RPI1->UART0_FBRD, 40); 

    // Enable FIFO & 8 bit data transmissio (1 stop bit, no parity). 
    mmio_write(PD_UART_INTERNAL_VALUES_RPI1->UART0_LCRH, (1 << 4) | (1 << 5) | (1 << 6)); 

    // Mask all interrupts. 
    mmio_write(PD_UART_INTERNAL_VALUES_RPI1->UART0_IMSC, (1 << 1) | (1 << 4) | (1 << 5) | (1 << 6) | 
         (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10)); 

    // Enable UART0, receive & transfer part of UART. 
    mmio_write(PD_UART_INTERNAL_VALUES_RPI1->UART0_CR, (1 << 0) | (1 << 8) | (1 << 9)); 
} 

Il y a une fonction secondaire, similaire pour la manipulation du UART INIT sur la ligne RPi 2 et 3 RPi. Avoir deux fonctions distinctes UART INIT est bien, et pas vraiment le problème. Le problème est de pouvoir distinguer les types de cartes. cela me sauverait beaucoup de tracas s'il y avait un moyen de déterminer la carte en cours d'utilisation. Ne pas pouvoir, signifie que j'ai besoin de faire un noyau de test séparé pour les cartes RPi 1, les cartes RPi 2-3 et toutes les autres cartes RPi, comme ODROID OC-2 par exemple. Si d'une manière ou d'une autre, il y avait un moyen de déterminer le type de carte, je pourrais l'utiliser comme une condition et charger les bonnes valeurs UART au démarrage, ce qui signifie que seul un fichier noyau unique est nécessaire. Une méthode qui pourrait fonctionner est le test basé sur le processeur, qui est unique entre chaque RPi Revision et les cartes alternatives. Sur les plates-formes x86, vous pouvez utiliser _RTDSC, mais je suis assez certain qu'aucune alternative de ce type n'existe sur les processeurs NON-x86/x86-64. Donc, la question que je pose est la suivante: existe-t-il un moyen, en assembleur ou en C, de vérifier le type de carte sur laquelle s'exécute l'utilisateur/le code? Puisque je construis un noyau de système d'exploitation, je n'ai pas accès aux bibliothèques de C de non-compilateur, ainsi le code de C devrait reporter à l'instruction d'assemblée volatile.

+1

Ensuite, prenez un coup d'œil sur le module du noyau Linux existant responsable de la création de cette information . Mais je ne comprends pas vraiment comment vous créez un noyau portable pour les différentes versions, car l'UART n'est vraiment pas la seule et principale différence. Différents RP ont des processeurs différents –

+0

@inifinitelyManiac l'utilisateur serait la personne avec le noyau de test sur le mSDHC. par exemple, j'ai un RPi 3b, mais un de mes amis a un RPi 1. Je cherchais un moyen de ne pas avoir à recompiler le noyau de test pour chaque variation du tableau. Je suppose que j'aurais dû être un peu plus précis là-bas. –

+0

@eugene sh. le compilateur utilisé est une cible générique: gcc-arm-none-eabi. Je suis bien conscient des différences intrinsèques entre les conseils, mais tous utilisent l'assemblage des bras. L'exécutable du noyau est portable dans ce seul sens. –

Répondre

1

Les noyaux ARM pour RP1, RP2 et RP2 v1.2 (à partir de) sont différents, à savoir. ARM11, Cortex-A7 et Cortex-A53. Mais l'ARM CP15 contient des informations sur l'architecture, le numéro de pièce et la révision du noyau, et selon la documentation ARM, la même instruction peut extraire les détails sur les deux cœurs.

MRC p15,0,<Rd>,c0,c0,0; reads Main ID register 

ARM11 retournerait-numéro de pièce 0xB76
Cortex-A7 donnerait 0xC07
et Cortex-A53 donnerait 0xD03.

S'il vous plaît voir ci-dessous deux références de infocenter.arm (je ne pouvais pas ajouter plus que deux liens, fournissant ainsi des références aux anciens et plus récents que ceux)

Références:
ARM1176JZF-S (PI-1):
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0301h/Bgbiddeb.html

Cortex-A53 (PI-2 v1.2 et suivants): http://infocenter.arm.com/help/topic/com.arm.doc.ddi0500g/BABFEABI.html

Espérons que cela aide.

[Merci à oldtimer pour les corrections]

+0

pi2 et p3 sont des cœurs différents, pi2 est un armv7 pi3 un armv8 (64 bits) –

+0

@ old-timer merci pour vos entrées. J'ai corrigé la réponse. – RuSh

+0

notez que le pizero est un pi1 rétréci donc il utilise la même puce que la pi1 et la même adresse de base périphérique dans l'espace d'adressage du bras. –

3

Puisque chaque génération de pi utilise un autre noyau de cpu du bras (un de ARMv6 spécifique puis un ARMv7 puis un ARMv8), vous pouvez facilement les détecter à partir d'un identifiant cpu registre.

.globl GETCPUID 
GETCPUID: 
    mrc p15,0,r0,c0,c0,0 
    bx lr 

Les différents noyaux renvoient des valeurs différentes

PI3 0x410FD034 
PI2 0x410FC075 
PI1/Zero 0x410FB767 

Et à partir de là, vous pouvez configurer votre base périphérique

if((id&0xFFFFFFFF)==0x410FB767) PBASE=0x20000000; 
else       PBASE=0x3F000000;