Туториал ChibiOS/HAL: регистры и битовые маски

Тема в разделе "ChibiOS/RTOS", создана пользователем radioengineer, 24 май 2017.

  1. radioengineer

    radioengineer Администратор Команда форума

    Сообщения:
    3.591
    Симпатии:
    357
    Адрес:
    Алматы
    Регистры и битовые маски

    1. Простейшие вещи, как известно, создают большие проблемы

    Когда я начинал работу со встраиваемыми системами мои знания о программировании были весьма элементарны, как в прочем и сейчас. Я часто использовал логические операторы такие как логическое НЕ (NOT), логическое ИЛИ (OR, ||), логическое И (AND, &&), но почти никогда не обращал внимание на битовые операторы.

    В Embedded разработке, битовые операторы широко используются в элементарном взаимодействии программно-аппаратной части устройства при записи регистров. Обращение к регистрам настолько простое, что я потратил лишь пару дней на их изучение. Общение с моими друзьями, использующими Arduino, показало суть этой проблемы. А проблема эта заключается в отсутствии элементарных знаний информатики и электроники. Таким образом, в этой статье мы будем обсуждать нечто очевидное для специалистов и не совсем очевидное для начинающих.

    2. Регистры

    В цифровой электронике регистры это специальные структуры для хранения битов информации таким образом, чтобы система могла записать или считать весь регистр, т.е. все биты одновременно. Тем не менее регистры используются не только как буфер для хранения байт информации. Они могут быть использованы также как статусные регистры (изменение состояние регистра говорит о каком либо произошедшем событии), в качестве регистров ввода-вывода (типа GPIO) и для конфигурации определенных настроек.
    Настройка периферийного устройства это всегда запись одного или нескольких бит в регистр. Тем не менее, различные библиотеки периферии зачастую инкапсулируют эти процедуры, скрывая их от программиста за уровнем абстракции. Практически всегда, если программисту необходим настроить периферию на какой-либо аппаратной платформе, он столкнется с записью конфигурационных бит в регистры. Длина регистров обычно равна длине слова (word) архитектуры процессора. В качестве примера рассмотрим регистр из микроконтроллера серии SAM:
    art_005_F7_reg.jpg
    Рисунок 1 — регистр SPI Chip Select контроллера Atmel SAM. Этот регистр длиной 32 бита и имеет 8 различных полей.

    По существу, конфигурирование данного регистра означает, что нам нужно собрать бит за битом целое значение в 32 бита, преобразовать это значение в десятичный или шестнадцатиричный вид для более короткой записи и записать его в регистр. Более того, если битам в регистре нужно поменять значение, то нам нужно считать данные из регистра, конвертировать их в бинарный вид, изменить нужные биты, снова конвертировать в короткую запись и записать значение в регистр. Рассмотрим следующий кусок кода:

    PHP:
    addr 0x40088030;
    value 147;
    WriteRegister (addrvalue);
    Такая запись практически ни о чем не говорит, не ясно какая конфигурация была произведена. Более функционален следующий вид записи:

    PHP:
    #define  SPI_Chip_Select_REG    0x40088030
    ...
    #define     SPI_CSR_CPOL                 0x01
    #define     SPI_CSR_ NCPHA               0x02
    ...
    #define     SPI_CSR_ BITS_0              0x10
    ...
    #define     SPI_CSR_ BITS_3              0x80
    ...
    WriteRegister(SPI_Chip_Select_REGSPI_CSR_BITS_3 SPI_CSR_BITS_0 |
                  
    SPI_CSR_ NCPHA SPI_CSR_CPOL);
    Здесь мы записываем в биты СPOL и CPHA "1" и BITS в 1001 (или 9). Это одно из практических применений битовых операторов.

    3. Побитовые и логические операторы

    Языки без явно описанного логического типа данных, такие как С90 и Lisp, могут представлять значения истины в виде других данных. Например язык С использует целочисленный тип данных, где выражения, такие как i < j, логические выражения с операторами && и || всегда истинны, если результат равен 1 и ложны при 0. Если эти выражения часть операторов if, while, for, то истинно любое значение отличное от 0.
    Любые логические операции и операторы с логическими типами данных всегда возвращают логическое значение 0 или 1, независимо от значений бит данных. Так 1001, 10000, 1, -5, -6 можно рассматривать как истинное значение и только 0 как ложное. !1001 и !(-2) возвращают 0, то есть являются ложными.

    Учитывая предыдущий код, который мы написали:

    SPI_CSR_BITS_3 | SPI_CSR_BITS_0 | SPI_CSR_ NCPHA | SPI_CSR_ CPOL
    Равносильно этому:
    0x80| 0x10| 0x02| 0x01
    или
    0b1000 0000 | 0b0001 0000 | 0b0000 0010 | 0b0000 0001
    результатом будет 0b1001 0011

    Используя побитовое ИЛИ (OR), мы можем устанавливать биты по одному в регистре. В следующем примере мы установим бит CPOL в 1, оставив другие без изменений:

    PHP:
    Value ReadRegister(SPI_Chip_Select_REG);
    WriteRegister(SPI_Chip_Select_REGValue SPI_CSR_ CPOL);
    Использую побитовое НЕ (NOT) и И (AND) мы можем устанавливать биты в 0. Рассмотрим пример:

    0b1101 1111 & 0b1011 1111

    Результатом операции станет значение 0b1001 1111. Кроме того второй оператор может быть получен в результате побитового НЕ (~0b0100 0000). Это означает что с помощью этого оператора можно установить биты в 0, оставив без изменения другие.

    PHP:
    Value ReadRegister(SPI_Chip_Select_REG);
    WriteRegister(SPI_Chip_Select_REGValue & (~SPI_CSR_ CPOL));
    В заключении можно сказать что битовые маски могут быть созданы с помощью операторов сдвига, так например 0х04 это результат операции 1<<3 или 0х0200 равносильно 1<<9.
    Buba_Chkhadze нравится это.
     

Поделиться этой страницей