Розвернути біти
Так чи інакше, а ця задачка вилазить.
В моєму випадкові потреба виникла тому, що Altera FPGA при завантаженні по SPI вимагає потік молодшим бітом вперед, а порт SSP мікроконтролерів LPC17 працює лише старшим бітом вперед. Якраз нещодавно на форумі хтось обурювався, що у STM8 USART в режимі SPI працює лише молодшим бітом вперед: «і кому такий SPI потрібен?». Та от, мені…
Як я вже писав у публікації Двійкові дані та програма мікроконтролера (це що, я так довго не повертався до цієї роботи?), можна було б зробити власну програму обробки конфігураційного масиву FPGA, в якій врахувати також і порядок бітів. Але пристрій може отримувати прошивки програмованої логіки ззовні, тому хотілося б приймати файли в такому вигляді, в якому їх видає Quartus. Менше буде плутанини.
На щастя, Cortex-M3 має спеціальну команду розвороту бітів. Ця команда міняє порядок бітів у 32-бітному регістрі, 0-вий біт стає 31-шим, 1-ий — 30-тим і так далі. Тобто для того, щоб розвернути біти в одному байті, результат команди rbit
треба зсунути вправо на 24 біти (тут і далі використовуються макроси з файлу від ARM core_cmIntsr.h
, який включається до файлу core_cm3.h
і вже через нього до LPC17xx.h
від NXP):
uint32_t v;
v = __RBIT(v) >> 24;
У кортексів, навіть у Cortex-M0, є ще команди обернення порядку байтів у 32-бітному та 16-бітному словах, rev
та rev16
відповідно. Основне їх призначення — перехід від мережевого (big-endian) до внутрішнього (little-endian) порядку байтів. Нам команда rev
допоможе парою команд розвернути біти відразу у чотирьох байтах, не міняючи їх порядку у слові:
uint32_t v;
v = __REV(__RBIT(v));
Так можна готувати дані для побайтового виводу конфігураційного масиву у FPGA.
Якщо ж хочеться використати 16-бітний режим SSP, то доведеться врахувати, що він, починаючи передачу зі старшого біту, розверне порядок байтів у парі. Тобто після реверсу порядку бітів (який одночасно зробить і реверс порядку байтів) слід просто взяти старші 16 біт 32-бітового слова. Це можна зробити зсувом на 16 біт.
Я ж завантажую у SSP по одному слову, тому зупинився на реверсі бітів у 16-бітному слові (половині регістра):
uint16_t *pdata;
uint32_t v = *pdata++;
v = __RBIT(v) >> 16;
Далі SSP виводить 16 біт змінної починаючи зі старшого, тобто два байти з конфігурації йдуть у потрібному порядку, спочатку молодший байт молодшим бітом вперед, за ним старший байт.