Я занимаюсь разработкой тестового ядра для устройств малины 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 должен будет отложить переход к инструкции по неустойчивой сборке.
Тогда взгляните на существующий модуль ядра Linux, ответственного за создание этой информации , Но я действительно не понимаю, как вы создаете портативное ядро для разных версий, поскольку UART действительно не единственное и основное отличие. Различные RPS имеют разные процессоры –
@inifinitelyManiac пользователь будет человеком с тестовым ядром на mSDHC. например, у меня есть RPi 3b, но у моего друга есть RPi 1. Я искал способ, которым мне не пришлось бы перекомпилировать тестовое ядро для каждого варианта платы. Наверное, я должен был быть более конкретным. –
@eugene sh. используемым компилятором является общая цель: gcc-arm-none-eabi. я хорошо осведомлен о внутренних различиях между досками, но все они используют Arm assembly. Исполняемый файл ядра переносится только в этом смысле. –