2017-02-07 16 views
4

Я занимаюсь разработкой тестового ядра для устройств малины Pi. При этом мне нужно настроить UART, чтобы мы могли записывать данные на устройство и получать данные, которые должны обрабатываться ядром. Я хочу, чтобы тестовое ядро ​​могло работать на нескольких устройствах Raspberry Pi. Существует небольшая проблема:Как определить версию платы Rasberry Pi с использованием кронштейна для крепления/C?

Адреса UART Разница между версиями. Например, адрес для RPi 1 линии UART GPIO является:

0x20200000 

Но адрес для UART GPIO на RPi 2 и RPi 3 линий:

0x3F200000 

Естественно, это означает, что должны быть две отдельные функции UART_INIT: 1 для устройств линии RPi 1 и 1 для RPi 2 и выше.

Ниже приведен образец кода обработки UART. Этот код изменен из кода, представленной 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)); 
} 

Существует второй, аналогичной функции для обработки УАПП INIT на линии RPi 2 и 3 RPi. Наличие двух отдельных функций UART INIT в порядке, и это не проблема. Проблема заключается в том, чтобы различать типы плат. это спасло бы меня от хлопот, если есть способ определить текущую используемую плату. Не будучи в состоянии, означает, что мне нужно сделать отдельное тестовое ядро ​​для плат RPi 1, плат RPi 2-3 и любых других плат RPi, таких как ODROID OC-2, например. Если бы каким-то образом был способ определить тип платы, я мог бы использовать его в качестве условия и загружать правильные значения UART при загрузке, а это означает, что требуется только один файл с уникальным ядром. Один из способов, который может работать, - это тестирование на базе процессора, которое является уникальным для каждого RPi Revision и альтернативных плат. На платформах x86 вы можете использовать _RTDSC, но я уверен, что таких альтернатив нет на процессорах NON-x86/x86-64.

Итак, вопрос, который я задаю, заключается в следующем: есть ли способ, либо в сборке, либо в C, который позволяет проверить, какой тип платы используется пользователем/кодом? Поскольку я создаю ядро ​​ОС, у меня нет доступа к библиотекам не компилятора C, поэтому код C должен будет отложить переход к инструкции по неустойчивой сборке.

+1

Тогда взгляните на существующий модуль ядра Linux, ответственного за создание этой информации , Но я действительно не понимаю, как вы создаете портативное ядро ​​для разных версий, поскольку UART действительно не единственное и основное отличие. Различные RPS имеют разные процессоры –

+0

@inifinitelyManiac пользователь будет человеком с тестовым ядром на mSDHC. например, у меня есть RPi 3b, но у моего друга есть RPi 1. Я искал способ, которым мне не пришлось бы перекомпилировать тестовое ядро ​​для каждого варианта платы. Наверное, я должен был быть более конкретным. –

+0

@eugene sh. используемым компилятором является общая цель: gcc-arm-none-eabi. я хорошо осведомлен о внутренних различиях между досками, но все они используют Arm assembly. Исполняемый файл ядра переносится только в этом смысле. –

ответ

1

ARM-сердечники для RP1, RP2 и RP2 v1.2 (далее) различны, а именно: ARM11, Cortex-A7 и Cortex-A53.

Но ARM CP15 содержит информацию о архитектуре, номере и ревизии ядра, а в соответствии с документацией ARM одна и та же инструкция может отображать детали на обоих ядрах.

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

ARM11 вернется неполный номер как 0xB76
Cortex-A7 даст 0xC07
и Cortex-A53 даст 0xD03.

Пожалуйста, смотрите следующие две ссылки из infocenter.arm (я не мог бы добавить еще, что две ссылки, поэтому предоставление ссылки на старые и последние из них только)

рекомендации:
ARM1176JZF-S (PI-1):
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0301h/Bgbiddeb.html

Cortex-A53 (PI-2 v1.2 и далее): http://infocenter.arm.com/help/topic/com.arm.doc.ddi0500g/BABFEABI.html

Надеюсь, это поможет.

[Благодаря старожила для коррекции]

+0

pi2 и p3 - разные ядра, pi2 - armv7 pi3 armv8 (64 бит) –

+0

@ старый таймер благодаря вашим входам. Я исправил ответ. – RuSh

+0

Обратите внимание, что pizero является сжатым вниз pi1, поэтому он использует тот же чип, что и pi1 и тот же периферийный базовый адрес в адресном пространстве руки. –

3

Поскольку каждое поколение пи использует другое ядро ​​центрального процессора от руки (конкретный ARMv6 затем ARMv7 и затем armv8), вы можете легко обнаружить их от центрального процессора ид регистр.

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

Различные ядра возвращают разные значения

PI3 0x410FD034 
PI2 0x410FC075 
PI1/Zero 0x410FB767 

И оттуда вы можете установить периферийное основание

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