Я пробовал выравнивать побайтно через pragme pack_mode. Не помогло. Все стало работать нормально когда удалил из структуры все BOOL, оставил только WORD и объединения. Необходимые битовые маски из BOOL собрал в коде программы в WORD. И в полях узла ModbusTCP_Slave_Device привязывал уже WORD-переменные, а не битовые.
Регистры.jpg
Кстати, если кто не знал (я точно не знал, но подозревал), то на скриншоте выше область памяти под %QW48 и под %QX96.0 - одна и та же область. Но слово "BOOL" справа от адресов %QX96.n сбивала с толку. Я думал под каждый %QX96.n отводится по байту и %QX96.0 и %QX96.1 будут иметь два разных адреса. Однако если через POINTER взять адреса %QX96.0 и %QX96.1, то они будут одинаковыми и %QX96.0 по %QX96.7 занимают 1 байт. Таким образом логичнее было бы разработчикам Codesys в соотнесении входов-выходов писать тип переменной не BOOL, а BIT.