Типы доступа к регистрам
В таблице регистра рядом с каждым полем стоит пометка: R/W, RO, WTC, rc_w1. Это тип доступа, и он меняет смысл записи: в одно поле запись 1 устанавливает бит, в другое — сбрасывает, а запись 0 вообще ничего не делает. Ошибиться здесь — значит сбросить чужой флаг прерывания.
Обновлено Редакция GAW
Тип доступа (access type) регистра или поля — правило, по которому на чтение и запись реагирует аппаратура. Его указывают в справочном руководстве у каждого поля: от простого «только чтение» до «сброс записью единицы». От типа зависит, каким кодом правильно менять поле.
Основные типы
| Обозначение ESP32 | Обозначение STM32 | Что происходит |
|---|---|---|
| RO | r | только чтение |
| R/W | rw | чтение и запись |
| WO | w | только запись; у STM32 чтение возвращает значение после сброса |
| W1C | rc_w1 | запись 1 в сам бит сбрасывает его, запись 0 не действует |
| W0C | rc_w0 | запись 0 сбрасывает бит, запись 1 не действует; у STM32 так устроены TIMx_SR и USART_SR |
| WT | rt_w (близкий смысл) | запись 1 порождает событие — импульс на шине — или сбрасывает связанное поле WTC |
| WTC | — | поле сбрасывается записью 1 в парное поле WT |
| RC | rc_r | бит сбрасывается при чтении |
| W1S, WS | rs | запись 1 (у WS — любая запись) устанавливает бит |
| W1T | t | запись 1 переключает бит |
| SS, SC | — | бит устанавливает или сбрасывает сама аппаратура по событию |
Источники: глоссарий типов доступа в TRM ESP32-S3 v1.8 и раздел 1.1 RM0090. Пара WT/WTC у Espressif — это флаги прерываний: например, у UART флаг UART_RXFIFO_FULL_INT_RAW имеет тип R/WTC/SS (его ставит аппаратура, а сбрасывает запись), а бит UART_RXFIFO_FULL_INT_CLR в регистре UART_INT_CLR_REG — тип WT: запись в него единицы сбрасывает флаг (TRM ESP32-S3, гл. 26).
Регистры W1TS и W1TC
Для выходов GPIO ESP32 есть отдельные регистры: GPIO_OUT_W1TS_REG (write 1 to set) и GPIO_OUT_W1TC_REG (write 1 to clear). Единица в бите W1TS устанавливает соответствующий бит GPIO_OUT_REG, единица в W1TC — сбрасывает, нули ничего не меняют; Espressif рекомендует именно этот способ (TRM ESP32-S3, гл. 6; регистры — на странице GPIO ESP32-S3). У STM32 ту же роль играет GPIOx_BSRR: ST подчёркивает, что запись в него — одна атомарная операция на шине и запрещать прерывания не нужно (RM0090, разд. 8.3.5).
Типичная ошибка
Флаги прерываний типа W1C сбрасывают прямой записью маски, а не операцией REG |= MASK: чтение-изменение-запись вернёт единицы во все флаги, которые были установлены в момент чтения, и сбросит их, хотя их ещё не обработали. Флаг, пришедший уже после чтения, при этом записывается нулём и не пострадает — для W1C и rc_w1 запись 0 ничего не делает (TRM ESP32-S3, с. 1520–1521; RM0090, разд. 1.1). С флагами rc_w0 у STM32 опасность обратная: REG &= ~MASK запишет 0 и во флаги, которые установились между чтением и записью, и они пропадут; такие флаги сбрасывают записью ~MASK без чтения (наш вывод из определений). Это частный случай состояния гонки. Как устроен доступ к регистрам в коде STM32, разобрано в статье «HAL, LL и регистры», маски полей собирает конструктор регистров.
Не путать
С атрибутами доступа к памяти в MPU — там речь о правах программы на области адресов, а тип доступа поля описывает поведение конкретного бита периферии.
Частые вопросы
Что значит W1C или rc_w1?
Бит сбрасывается, если записать в него единицу, а запись нуля его не меняет (TRM ESP32-S3; RM0090, разд. 1.1). Так устроены флаги прерываний и ошибок: чтобы сбросить только один флаг, пишут маску с единицей в его позиции, остальные флаги не трогаются.
Почему нельзя сбросить W1C-флаг через чтение-изменение-запись?
Операция REG |= MASK читает регистр, где могут стоять и другие флаги, и записывает их обратно единицами — тем самым сбрасывает и их, хотя их ещё не обработали (наш вывод из определения W1C). Правильно — прямая запись маски: REG = MASK.
Зачем в ESP32 отдельные регистры W1TS и W1TC?
Чтобы установить или сбросить отдельные выводы одной записью: единица в бите GPIO_OUT_W1TS_REG устанавливает соответствующий бит GPIO_OUT_REG, в GPIO_OUT_W1TC_REG — сбрасывает, нули ничего не меняют (TRM ESP32-S3, гл. 6). Espressif рекомендует именно этот способ. Тот же смысл у GPIOx_BSRR в STM32: ST пишет, что для побитовой записи не нужно запрещать прерывания.
Источники
- Espressif. ESP32-S3 Technical Reference Manual, Version 1.8, Glossary «Access Types for Registers» — гл. 26: UART_INT_CLR_REG — WT, флаги *_INT_RAW — R/WTC/SS; с. 1520–1521: RO, WO, R/W, W1 (однократная запись), SS/SC (аппаратная установка/сброс), RC (сброс чтением), WC (сброс любой записью), W1C (сброс записью 1), W0C, W1S, WT (запись 1 — событие или сброс связанного поля WTC), W1T (переключение записью 1); гл. 6: GPIO_OUT_W1TS_REG и GPIO_OUT_W1TC_REG (WO) — запись 1 в бит устанавливает или сбрасывает соответствующий бит GPIO_OUT_REG, рекомендуемый способ
- STMicroelectronics. RM0090 Rev 21. Reference manual: STM32F405/415, STM32F407/417, STM32F427/437 and STM32F429/439 — разд. 1.1: rw, r, w, rc_w1 (сброс записью 1, запись 0 без эффекта), rc_w0 (сброс записью 0; так устроены флаги TIMx_SR, разд. 17.4.5 и 18.4.5, и USART_SR, разд. 30.6.1), rc_r (сброс чтением), rs, rt_w, t (переключение записью 1); разд. 8.3.5: GPIOx_BSRR — атомарная побитовая запись, не нужно запрещать прерывания
Нашли ошибку?
Смотрите также
- Атомарная операцияОперация, которую прерывание не застанет наполовину
- Состояние гонкиОшибка, зависящая от момента срабатывания прерывания
- HAL, LL или регистрыУровни STM32Cube, что делает HAL, правила совмещения, один код тремя способами
- Конструктор регистров AVRБиты регистра → hex, строка на C и ассемблере
- ПрерываниеЗапрос периферии, вектор и обработчик прерывания
- Чтение-модификация-записьИзменение части регистра в три шага и связанные с этим гонки