Регистры
Эта глава — технический разбор. Её можно пока пропустить и вернуться к ней позже, если захотите. Впрочем, здесь много полезного, поэтому рекомендую погрузиться.
Пора разобраться, что на самом деле происходит при вызове display_pins.row1.set_high() или button_a_pin.is_high().
Если коротко, вызов display_pins.row1.set_high() просто записывает значения в особые области памяти. Перейдите в каталог 09-registers и пройдём стартовый код (src/main.rs) оператор за оператором.
#![no_main]
#![no_std]
#[allow(unused_imports)]
use registers::entry;
#[entry]
fn main() -> ! {
registers::init();
unsafe {
// Волшебный адрес!
const PORT_P0_OUT: u32 = 0x50000504;
// Включаем верхний ряд
*(PORT_P0_OUT as *mut u32) |= 1 << 21;
// Включаем нижний ряд
*(PORT_P0_OUT as *mut u32) |= 1 << 19;
// Выключаем верхний ряд
*(PORT_P0_OUT as *mut u32) &= !(1 << 21);
// Выключаем нижний ряд
*(PORT_P0_OUT as *mut u32) &= !(1 << 19);
}
loop {
core::hint::spin_loop();
}
}
Что здесь за магия?
Адрес 0x50000504 указывает на регистр. Регистр — это особая область памяти, которая управляет периферией. Периферия — это электронный блок, расположенный рядом с процессором внутри корпуса микроконтроллера, который добавляет процессору дополнительные возможности. Ведь сам по себе процессор умеет только считать и выполнять логические операции.
Этот конкретный регистр управляет выводами (pins) GPIO — универсального ввода-вывода (GPIO является периферией) — и может использоваться, чтобы выставлять каждый из этих выводов в низкий или высокий уровень.
(В nRF52833 больше 32 GPIO, но процессор 32-битный. Поэтому выводы GPIO разбиты на две группы, «P0» и «P1», с набором регистров для чтения, записи и настройки каждой группы. Адрес выше — это адрес выходного регистра для выводов P0.)
Отступление: светодиоды, цифровые выходы и уровни напряжения
Выставлять? Вывод? Низкий? Высокий?
Вывод — это электрический контакт. У нашего микроконтроллера их несколько, и некоторые из них подключены к светодиодам (Light Emitting Diode, LED). Светодиод излучает свет, когда на него подано напряжение. Как следует из названия, светодиод также работает как «диод»: он пропускает электрический ток только в одном направлении. Подключите светодиод «в прямом направлении» — и он светится. Подключите «в обратном» — ничего не произойдёт.
К счастью, выводы микроконтроллера подключены так, что светодиоды можно включать правильной стороной. Нужно лишь подать на выводы достаточное напряжение, чтобы зажечь светодиод. Выводы, к которым подключены светодиоды, обычно настраивают как цифровые выходы: они могут выдавать два уровня напряжения — «низкий», 0 В, или «высокий», 3 В. Высокий уровень зажигает светодиод, а низкий — гасит.
Эти состояния «низкий» и «высокий» напрямую соответствуют понятиям цифровой логики: «низкий» — это 0 или false, а «высокий» — 1 или true. Поэтому такая конфигурация вывода и называется цифровым выходом.
Противоположность цифровому выходу — цифровой вход. Так же как цифровой выход может быть 0 или 1, цифровой вход тоже может быть 0 или 1. Разница в том, что цифровые выходы задают напряжение, а цифровые входы считывают его. Когда микроконтроллер считывает уровень напряжения выше порога высокого уровня, он интерпретирует его как 1, а когда уровень ниже порога низкого уровня — как 0.
Хорошо. Но как узнать, что делает этот регистр? Пора обратиться к RTRM (Read The Reference Manual, «прочитай справочное руководство»)!