Здравствуйте. Купил на ebay радиомодули RF-2400 (построены на чипе BK2421). Не могу разобраться с отправкой-приемом. Видал кучу библиотек, но все были под PIC или AVR.
Переделал по STM. Изучил даташит, инициализация вроде верная - на приемнике и передатчике одинаковые параметры. Думаю есть какой-то маленький нюанс, который не учел.
При отправке на передатчике получаю статус 1E - превышен максимальный лимит попыток передачи. На приемнике посылки нету - прерывания на ноге IRQ нету.
Может кто имел с ними дело, подскажите, что я не учел.

Начну с того, что инициализация (записи в банки регистров) для разных банок разная. Команды все передаются от старшего бита к младшему. В Bank0 и Bank1 с 9 по 14 регистры передача идет от младшего байта к старшему. С 0 по 8 регистр Bank1 передача идет от старшего байта к младшему.

Ну и в принципе по отладчику проверял, все условия передачи учитываются, считываю все регистры Bank0 после записи - все записано верно. С Bank1 считывать не дает - он только для записи.

Наверное сперва напишу алгоритм общения с RF-2400, т.к. в команды выполняются, с модулем общаюсь хорошо, т.е. в коде ошибок не должно быть. Пытаюсь передать 1 байт "\x37"

Инициализация RF-2400:

1. Устанавливаем линию CE
2. Ждем 2 сек для запуска модуля (везде разные цифры, кто 100мс ждет, кто 200мс, кто 500мс. Я не тороплюсь - пусть будет 2000мс. Отправляю команду ActivateCmd с параметром 0x73. Если честно, так и не понял, что это дает. Но так делают все.
3. Переключаемся на Bank0
3.1 Опускаем линию CE
3.2 Ждем 50мс
3.3 Читаем статус
3.4 Если стоит Bank0, ничего не делаем, если Bank1 - переключаемся командой ActivateCmd с параметром 0x53
3.5 устанавливаем линию CE
3.6 Ждем 2 сек
4. Инициализируем модуль с параметрами Bank0:
CODE
ConfigRegValues = 0x0B, // Prim_RX, Power up, CRC 1 bytes, Enable CRC, Int RX, Int TX, Int RX_DR
EnableAutoAckRegValues = 0x3f, // Включить автоподтверждение для всех "pipe"
EnableRxAdressRegValues = 0x01, // включить data pipe 0
SetupAdressWidthRegValues = 0x03, // ширина адреса 5 байт
SetupRetryRegValues = 0x3F, // Повтор передачи через = 1000us, 15 попыток
RfChannelRegValues = 0x20, // канал для передачи - 32
RfSetupRegValues = 0x37, // 1Mbps, output power=5dBm, LNA=HIGHT
StatusRegValues = 0x70, // Флаги прерываний RX, TX, MAX_TX очищены
// MAX_RT - превышение максимума кол-ва попыток передачи
ObserveTxRegValues = 0x00, // только чтение
CarrierDetectRegValues = 0x00, // только чтение
RxAddress2Values = 0xc3, //
RxAddress3Values = 0xc4, //
RxAddress4Values = 0xc5, //
RxAddress5Values = 0xc6, //
RxDataLength0Values = 0x20, // RX Payload Length = 32
RxDataLength1Values = 0x20, //
RxDataLength2Values = 0x20, //
RxDataLength3Values = 0x20, //
RxDataLength4Values = 0x20, //
RxDataLength5Values = 0x20, //
DynamicPayloadValues = 0x3f,
FeatureValues = 0x04,
FifoStatusRegValues = 0x11

/*The Rx Address 5 bytes*/
const unsigned char RX_Address0[5] = { 0x3a, 0x3b, 0x3c, 0x3d, 0x01 };

/*The Tx Address 5 bytes*/
const unsigned char TX_Address0[5] = { 0x3a, 0x3b, 0x3c, 0x3d, 0x01 };

5. Переключаемся на Bank1
6. Инициализируем модуль с параметрами Bank1:
CODE
/*0*/ 0xE2014B40,
/*1*/ 0x00004BC0,
/*2*/ 0x028CFCD0,
/*3*/ 0x41390099,
/*4*/ 0x0B869ED9, //Change REG4[29:27] from 00 to 11
/*5*/ 0xA67F0624, //Disable RSSI measurement
/*6*/ 0x00000000,
/*7*/ 0x00000000,
/*8*/ 0x00000000,
/*9*/ 0x00000000,
/*0A*/ 0x00000000,
/*0B*/ 0x00000000,
/*0C*/ 0x00127300,
/*0D*/ 0x36B48000,
};

unsigned char Bank1_Reg14[Reg14Size]=
{
0x41,0x20,0x08,0x04,0x81,0x20,0xCF,0xF7,0xFE,0xFF,0xFF //LSB first
};

7. Переключаемся на Bank0 для дальнейшего считывания статуса.

На этом инициализация закончена. В дальнейшем алгоритм отправки данных по нажатию кнопки:
8. Отправляем пакет:
8.1 Переключаемся в режим передачи
8.1.1 Опускаем линию CSN
8.1.2 Отправляем команду FlushTx (0xE1)
8.1.3 Устанавливаем линию CSN
8.1.4 Опускаем линию CE
8.1.5 Ждем 200мс
8.1.6 читаем GONFIG и устанавливаем последний бит (PRIM_RX) в 0 для активации режима передачи
8.1.7 Поднимаем линию CE
8.1.8 Ждем 2 сек
8.2 Читаем FIFO_STATUS, получаем 10001 (0x11) - установлены TX_FULL и RX_EMPTY
8.3 Если 5-й бит (TX_FULL) установлен:
8.3.1 Опускаю линию CSN
8.3.2 Отправляю WriteTxDataCmd (0xA0)
8.3.3 Пока не закончится указанное число байт - отправляю содержимое буфера
8.3.4 Поднимаем линию CSN
9. Ждем 200мс и читаем статус. Получаем 1E - превышен лимит попыток отправки.

Ну собственно вот и все. Код для приемника и передатчика один и тот же. Приемник есс-но в режиме приема - насилу ему указываю SwitchToRxMode(), несмотря на то, что он уже по-умолчанию инициализируется с этим режимом, чтоб уж наверняка.

Может быть разная адресация - ставил разные: все адреса одни и те же; ставил перекрестные (условно: передатчик RX =0, TX=1. Приемник RX=1, TX=0). Читал на казусе, что адреса лучше ставить начиная с E7 для лучшей преамбулы и т.д. Что я не учел?

Ну и коды:

Функция передачи команды в RF-2400
CODE
Код
/*-------------------------------------------------------------------------------------------*/
/* Записывает значение в RF-2400 и возвращает ответ                                        */
/* Принимает:   value: адрес регистра                                                    */
/* Возвращает:  содержимое регистра    DR                                                */
/*----------------------------------------------------------------------------------------------------------*/
/* Команда передается от старшего бита к младшему, поэтому реализуем ручной SPI                    */
/*----------------------------------------------------------------------------------------------------------*/
unsigned char SPI_RW(unsigned char value)
{
    unsigned char res = 0;                    // вывод полученного результата
    unsigned char i = 0x80;                    // переменная для побитовой передачи и чтения данных
    unsigned char bit_ctr=0;                // счетчик переданных/полученных байт
    for(bit_ctr=0;bit_ctr<8;bit_ctr++)            // передача 8-ми бит
    {
        if(value & 0x80)                    // сравниваем старший бит с '1000 0000'
        {
            SET_MOSI();                // если старший бит равен единице, поднимаем MOSI - передаем '1'
        }
        else
        {
            CLR_MOSI();                // иначе опускаем MOSI - передаем '0'
        }
        value = (value << 1);                // сдвигаем наш байт на единицу влево (передаем следующий бит)
        SET_SCK();                        // устанавливаем SCK в '1'
        if(GET_MISO())
        {
            res |= i;                            // Записываем принятый бит
        }
        CLR_SCK();                        // бит передан, опускаем SCK
        i >>= 1;
    }
    return(res);                            //возвращаем принятый байт
};
</div>

Функция записи значения в регистр:
CODE
Код
/*----------------------------------------------------------------------------------------------*/
/* Записывает значение 'value' в регистр 'reg' в RF-2400                                */
/* Принимает:   reg: адрес регистра                                            */
/* Возвращает:  ничего                                                    */
/*----------------------------------------------------------------------------------------------*/
void SPI_Write_Reg(unsigned char reg, unsigned char value)
{
    delay_ms(10);
    CLR_SS();                        // опускаем CSN, инициируем передачу
    SPI_RW(reg);                    // отсылаем адрес регистра
    SPI_RW(value);                    // отсылаем значение регистра
    SET_SS();                        // поднимаем CSN, заканчиваем передачу
};


Функция записи массива байт в RF-2400:
CODE
Код
/*----------------------------------------------------------------------------------------------*/
/* Записывает массив байт в регистр RF-2400                                    */
/* Принимает:   reg: адрес регистра                                            */
/*                pBuffer: массив для отправки                                */
/*                Length: размер массива                                    */
/* Возвращает:  ничего не возвращает                                            */
/*----------------------------------------------------------------------------------------------*/
void SPI_Write_Buf(unsigned char reg, unsigned char *pBuffer, unsigned char Length)
{
    CLR_SS();                                // опускаем CSN, инициируем передачу
    SPI_RW(reg);                            // отсылаем адрес регистра
    while(Length--)                            // пока длина не равна нулю
    {
        SPI_RW(*pBuffer++);                        // отсылаем байты
    }
    SET_SS();                                // поднимаем CSN, заканчиваем передачу
}


Функция для отправки данных по радиоканалу:
CODE
Код
/*----------------------------------------------------------------------------------------------*/
/* записывает данные в буфер передачи модуля                                    */
/* Принимает: *buffer - ссылка на массив для передачи,     size - длина массива                    */
/* Возвращает:  если буфер передачи не полон: 1                                    */
/*                 если буфер передачи полон: 0                                */
/*----------------------------------------------------------------------------------------------*/
unsigned char Write(void *buffer, unsigned char size)
{
    SwitchToTxMode();
    unsigned char fifoStatus = SPI_Read_Reg(ReadRegCmd | FifoStatusReg);
    if(!(fifoStatus & 0x20 ))
    {
        SPI_Write_Buf(WriteTxDataCmd, (unsigned char*)buffer, size);
        return 1;
    }
    return 0;
}


Переключение в режим приемника:
CODE
Код
/*----------------------------------------------------------------------------------------------*/
/* Процедура переключения в режим приема                                        */
/* Принимает: ничего                                                                                        */
/* Возвращает:  ничего не возвращает                                            */
/*----------------------------------------------------------------------------------------------*/
void SwitchToRxMode(void)
{
    unsigned char value;
    CLR_SS();                                        // опускаем CSN, инициируем передачу
    SPI_RW(FlushRxCmd);                                // очищаем буфер приема
    SET_SS();                                        // поднимаем CSN, заканчиваем передачу
    value = SPI_Read_Reg(ReadRegCmd | StatusReg);                   // читаем StatusReg
    value = value & 0x70;                                         // устанавливаем последний бит в '0' (PRIM_RX)
    SPI_Write_Reg(WriteRegCmd | StatusReg, value );            // clear RX_DR or TX_DS or MAX_RT interrupt flag
    CLR_CE();
    delay_ms(200);
    value = SPI_Read_Reg(ReadRegCmd | ConfigReg);            // читаем ConfigReg
    value = value | 0x01;                                // устанавливаем последний бит в '1' (PRIM_RX)
      SPI_Write_Reg(WriteRegCmd | ConfigReg, value );             // устанавливаем PRX
    SET_CE();
    delay_ms(2000);
}


Переключение в режим передатчика:
CODE
Код
/*----------------------------------------------------------------------------------------------*/
/* Процедура переключения в режим передачи                                    */
/* Принимает: ничего                                                                                    */
/* Возвращает:  ничего не возвращает                                            */
/*----------------------------------------------------------------------------------------------*/
void SwitchToTxMode(void)
{
    unsigned char value;
    CLR_SS();                                        // опускаем CSN, инициируем передачу
    SPI_RW(FlushTxCmd);                                // очищаем буфер передачи
    SET_SS();                                        // поднимаем CSN, заканчиваем передачу
    CLR_CE();                                        // очищаем линию CE
    delay_ms(200);
    value = SPI_Read_Reg(ReadRegCmd | ConfigReg);            // читаем ConfigReg
    value = value & 0xfe;                                         // устанавливаем последний бит в '0' (PRIM_RX)
      SPI_Write_Reg(WriteRegCmd | ConfigReg, value );             // устанавливаем PTX
      value = SPI_Read_Reg(ReadRegCmd | ConfigReg);            // читаем ConfigReg
    SET_CE();                                        // поднимаем CE в '1'
    delay_ms(2000);
}


Переключение банков регистров:
CODE
Код
/*----------------------------------------------------------------------------------------------*/
/* Процедура переключение между Bank1 и Bank0                                    */
/* Принимает:   номер банка:                                                                            */
/*                            1:register bank1                                */
/*                            0:register bank0                                */
/* Возвращает:  ничего не возвращает                                            */
/*----------------------------------------------------------------------------------------------*/
/* переключение банков должно осуществляться при линии CE (EnablePin)                */
/* установленной в низкий уровень                                            */
/*----------------------------------------------------------------------------------------------*/
void SwitchCFG(unsigned char cfg)
{
    unsigned char tmp = 0;
    CLR_CE();
    delay_ms(50);
    tmp = SPI_Read_Reg(ReadRegCmd | StatusReg);            //читаем STATUS
    tmp = tmp & 0x80;                                //смотрим старший бит 'RBANK'
    tmp = (tmp >> 7);                                //сдвигаем полученный бит вправо, чтобы нормально сравнивать
    if (cfg != tmp)                                    //если устанавливаемый и установленный биты различаются
    {
        SPI_Write_Reg(ActivateCmd, 0x53);                //отправляем команду ActivateCmd с параметром 0x53 для переключения банка
    }
    tmp = SPI_Read_Reg(ReadRegCmd | StatusReg);            //читаем STATUS
    SET_CE();
    delay_ms(2000);
}