#define SYSCON_BASE (0x40000000u)
Это просто указывает, что по физическому адресу 0x40000000
.
#define SYSCON ((SYSCON_Type *)SYSCON_BASE)
Это преобразует целочисленную константу 0x40000000u
в указатель на структуру с помощью приведения.Он на самом деле ничего не выделяет - фактические регистры уже выделены как аппаратные средства отображения памяти.
Проще говоря, он говорит: «по адресу 0x40000000 есть аппаратное периферийное устройство SYSCON
» (что бы это ни было, какой-нибудь таймер?).Это распространенный сценарий, когда у вас есть несколько аппаратных периферийных устройств одного и того же типа внутри MCU (много SPI, ADC и т. Д.), Каждый с одинаковым расположением регистров, но найденный по разным адресам.Мы можем использовать один и тот же тип структуры для каждого такого периферийного устройства, а также один и тот же код драйвера.
Сама структура будет иметь карту памяти, которая на 100% соответствует макету регистра.Здесь важно убедиться, что заполнение / выравнивание не приводит к ошибкам, но, надеюсь, производитель микроконтроллеров подумал об этом (хотя и не принимайте это как должное).
Предполагая, что SDIOCLKSEL
имеет регистрсмещение 0x10
, затем, когда вы набираете SYSCON->SDIOCLKSEL = some value;
, вы получаете машинный код, подобный этому (псевдо-ассемблерный код):
LOAD 0x40000000 into index register X
LOAD 0x10 into register A
ADD A to X
MOVE some value into the address of X
(ARM получил специальные инструкции, которые могут перемещаться и т.д. на основе смещения, поэтомув действительном машинном коде может быть меньше инструкций. Последующие обращения к регистру могут оставить «X» нетронутым и использовать этот базовый адрес повторно для эффективного кода.)
Спецификатор __IO
- это просто скрытие раздувания кода volatile
.
Причина, по которой вы получаете ошибку при попытке «записи непосредственно в структуру», заключается просто в том, что вы не можете выполнить код вне всех функций, это не имеет ничего общего с этой структурой.