Мне нужно передавать последовательные данные из аппаратного модуля SPI. Этот модуль SPI принимает 16-разрядные слова и сначала передает их MSB.
Для подачи в модуль SPI я подготовил массив из 16-разрядных целых чисел.
Вот сложная часть: данные то, что я собираюсь передавать из модуля SPI, не состоит из слов шириной 16 бит. Вместо этого необходимо вывести 588 битов в 68 кодовых словах следующим образом:
Первое слово, codeIndex = 0, имеет ширину 24 бита. Каждое другое слово (codeIndex = x для всех нечетных чисел x) имеет ширину 3 бита. Все Остальные кодовые слова (codeIndex = x для всех ненулевых четных чисел) имеют ширину 14 битов
Интерфейс SPI должен последовательно выводить все эти кодовые слова без добавления или пропуска битов. Это означает, что первое 16-разрядное слово, которое я отправляю интерфейсу SPI, должно быть самыми значимыми 16 битами 24-битного codeIndex = 0, а следующее 16-битное слово будет оставшимися восемью битами codeIndex = 0, за которыми следует всеми тремя битами codeIndex = 1, за которыми следуют пять старших значащих битов codeIndex = 2, и следующее 16-битное слово, отправляемое на интерфейс SPI, завершит sh off codeIndex = 2 и т. д.
Я придумал подход для этого, который интенсивно использует двоичные операторы ИЛИ и побитовые сдвиги, но, похоже, должен быть более быстрый способ сделать это, манипулируя указателями или чем-то подобным.
Мой подход использует справочную таблицу. Каждая строка справочной таблицы определяет 16-битное слово с точки зрения количества нерегулярных кодовых слов в нем, каких кодовых слов в нем и побитовых смещений, которые должны быть применены к этим кодовым словам, прежде чем их будут OR в 16. слово. Поскольку 588 бит заполняют ровно 36,75 16-битных слов, я сделал эту таблицу длиной четыре итерации, чтобы идеально заполнить 147 16-битных слов. Из приведенного ниже кода видно, что я развернул несколько циклов в программе, чтобы попытаться ускорить его.
void fillBuffer(volatile uint16_t *buf) {
#define THIS_CODE_INDEX *codeIndex
#define THIS_CODE_OFFSET *codeOffset
//is the codeword merging bits?
#define CODE_SELECT_ITERATION \
if ( (THIS_CODE_INDEX & 1) == 1) { \
codeWord = mBitPattern[frame.mBits[(THIS_CODE_INDEX-1)>>1]];\
}\
/*is it a normal data word?*/\
else if (THIS_CODE_INDEX > 2) {\
codeWord = efmCode[frame.data[(THIS_CODE_INDEX>>1)-1]];\
}\
/*is it the sync word?*/\
else if (THIS_CODE_INDEX == 0) {\
codeWord = 0b100000000001000000000010;\
}\
/*it must be the control bits*/\
else {\
if (frameIndex >= 2) { /*if this is the third frame or beyond,*/\
codeWord = efmCode[frame.data[(THIS_CODE_INDEX>>1)-1]];\
}\
else if (frameIndex==0) { /*if it's the first frame,*/\
codeWord = 0b00100000000001; /*use s1*/\
}\
else { /*if it's the second frame,*/\
codeWord = 0b00000000010010; /*use s2*/\
}\
}\
#define CODE_OUTPUT_ITERATION(n) \
if (THIS_CODE_OFFSET < 0) buf[n] |= ((uint16_t) (codeWord >> (THIS_CODE_OFFSET*-1)));\
buf[n] |= ((uint16_t) (codeWord << THIS_CODE_OFFSET));
#define THIS_CODE_COUNT wordCount
#define FRAME_ITERATION(n) \
int8_t wordCount = decompTable[n][0];\
buf[n]=0;\
\
/*for each codeword that makes up this 16 bit frame:*/\
codeIndex = &decompTable[n][1];\
codeOffset = &decompTable[n][2];\
\
{\
CODE_SELECT_ITERATION\
CODE_OUTPUT_ITERATION(n)\
\
if (THIS_CODE_COUNT > 1){\
codeIndex+=2;\
codeOffset+=2;\
\
CODE_SELECT_ITERATION\
CODE_OUTPUT_ITERATION(n)\
\
if (THIS_CODE_COUNT > 2) {\
codeIndex+=2;\
codeOffset+=2;\
\
CODE_SELECT_ITERATION\
CODE_OUTPUT_ITERATION(n)\
}\
}\
}\
uint32_t codeWord;
const int8_t *codeIndex = &decompTable[0][1];
const int8_t *codeOffset = &decompTable[0][2];
for (uint8_t i = 0; i < 37; i++) {
FRAME_ITERATION(i)
}
frameIndex++;
for (uint8_t i = 37; i < 74; i++) {
FRAME_ITERATION(i)
}
frameIndex++;
for (uint8_t i = 74; i < 111; i++) {
FRAME_ITERATION(i)
}
frameIndex++;
for (uint8_t i =111; i < 147; i++) {
FRAME_ITERATION(i)
}
}
Надеюсь, это не так уж и грязно.
Кажется, это так тип проблемы возник бы где-то, прежде чем я дошел до этого, хотя. Есть ли более быстрый способ выполнить этот расчет?