В ядрах ARM Cortex есть удобный способ для доступа к отдельным битам регистров. Каждый бит получает свой виртуальный регистр, в который можно записать 0 или 1.

Номера регистров битбэндинга формируются так:

0x42000000 + (регистр - 0x40000000) * 0x20 + номер_бита * 4.

Использование битбэндинга

Рассмотрим пример. Вам нужно выполнить операцию

GPIOC->CRH |= GPIO_CRH_MODE9_0;

Эта операция в ассемблерном коде занимает 6 полуслов = 12 байт:

0x4815          LDR.N    R0, [PC, #0x54]
0x6800          LDR      R0, [R0]
0xf050 0x0010   ORRS.W   R0, R0, #16
0x4913          LDR.N    R1, [PC, #0x4C]
0x6008          STR      R0, [R1]

Теперь то же самое через битбэндинг. Требуется установить четвёртый бит регистра № 0x40011004, вычисляем адрес бита: 0x42000000 + (0x40011004 — 0x40000000) * 0x20 + 4 * 4 = 0x42220090. Устанавливаем бит (достаточно записать 1 в этот регистр):

*(uint32_t*)0x42220090 = 1;

Ассемблерный код теперь занимает в два раза меньше места:

0x2001          MOVS     R0, #1
0x4914          LDR.N    R1, [PC, #0x50]
0x6008          STR      R0, [R1]

Для удобства вычислений я сделал онлайн-калькулятор битбэндинга, он даже сразу генерирует код.