Как грамотно корректировать частоту SX1276 при LoRa режиме?

Тема в разделе "Программное обеспечение для Semtech", создана пользователем John, 14 апр 2017.

  1. John

    John New Member

    Добрый день!
    Не поможет ли кто разобраться с программированием SX1276 в режиме LoRa приёма?
    (В режиме передачи - работает как положено, - видно по спектру).
    Насколько я понял DataSheet в микросхеме в режиме LoRa разомкнутая петля ФАПЧ,
    'замыкать' которую надо программисту.
    В результате моей корреции частоты принимается 1-2 пакета и частота уходит
    катастрофически, приём прекращается.
    В DataSheet приведена формула для корректировки частоты:

    Ferr = (([0x28 (4 разр.), 0x29, 0x2A] * 2^24)/Fxtal) * (BW [KHz]/500)

    Посчитал по этой формуле коэффициенты для каждого из BW
    //
    // Frequency correction coefficients.
    //
    const double K_f [8] = {0.008192,
    0.010923,
    0.016384,
    0.021845,
    0.032768,
    0.043691,
    0.065536,
    0.131072};

    Вот мой исходный код на приём. Пробовал долго - видны следы попыток.
    //
    // Search for the received packet. The process lasts for 100 * Wait mS.
    //**************************************************************************
    //
    unsigned char Srch_Rec (unsigned char Wait)
    {
    unsigned char i = 0; // Счётчик циклов приёма.
    unsigned long Cnt = 0; // Используется для индикации процесса.
    unsigned char R_Stat = 0; // Считанный статус приёмника.
    unsigned char Work = 0; // Рабочая переменная для считывания 'длинных' данных по шине SPI.
    unsigned long Frq = 0; // Считаннное значение текущей частоты.
    unsigned long F_Err = 0; // Считанное значение корректировки частоты.
    unsigned long F_Cor = 0; // Перессчитанное по формуле значение корректировки частоты.
    unsigned char Mod_Stat = 0; // Считанный статус Модема.

    // (Можно сократить число переменных, но так удобнее отслеживать процесс).

    //
    //--------------------------------------------------------------------------
    //

    if (Wait == 0) // Корректирую, сколько ждать пакет, не 0, а то слишком долго.
    {
    Wait = 1;
    }

    // Wait of the packet receive.

    i = 0; // Обнуляю счётчик циклов приёма.
    do
    {

    Mod_Stat = RFM_Rd_Data (0x18); // Читаю состояние модема, чтобы убедиться.
    // что он принимает преамбулу, так как только тогда
    // корректировочные данные в регистре 0x2A, 0x29, 0x28 верны.

    // Read of the Frequency Error only in preamble receiving modem status.

    if ((Mod_Stat & 0x01) == 0x01)
    {
    Work = RFM_Rd_Data (0x28); // Читаю и 'собираю' корректироввочные значения.
    F_Err = Work;
    F_Err = F_Err << 8;
    Work = RFM_Rd_Data (0x29);
    F_Err = F_Err | Work;
    F_Err = F_Err << 8;
    Work = RFM_Rd_Data (0x2A);
    F_Err = F_Err | Work;

    // Frequency coorection.

    if (F_Err != 0)
    {
    Ind_Hex (235, 58, F_Err, WHITE, BLACK); // Индицирую корректировку.

    Work = RFM_Rd_Data (0x06); // Читаю текущее значение частоты.
    Frq = Work;
    Frq = Frq << 8;
    Work = RFM_Rd_Data (0x07);
    Frq = Frq | Work;
    Frq = Frq << 8;
    Work = RFM_Rd_Data (0x08);
    Frq = Frq | Work;


    if ((F_Err & 0x80000) == 0x0) // Корректировочное значение положительно (используется только 4 разряда в старшем байте)?
    {
    F_Cor = ceil (K_f[RFM95_Regime] * F_Err); // Вычисляю по указанной формуле смещение частоты.
    Frq = Frq - F_Cor; // Вычитаю корректировку и3 значания несущей.
    }
    else
    {
    F_Err = ((F_Err ^ 0xFFFFF) & 0xFFFFF); // Если отрицательно, то перевожу в абсолютное значение.
    F_Cor = ceil (K_f[RFM95_Regime] * F_Err); // Вычисляю по указанной формуле смещение частоты.
    Frq = Frq + F_Cor; // Добавляю корректировку к значанию несущей.
    }

    RFM_Set_Frq (((Frq >> 16) & 0xFF), ((Frq >> 8) & 0xFF), (Frq & 0xFF)); // Выставляю скорректированное значение частоты.

    Work = RFM_Rd_Data (0x06); // На всякий случай, читаю и индицирую, что получилось.
    Frq = Work;
    Frq = Frq << 8;
    Work = RFM_Rd_Data (0x07);
    Frq = Frq | Work;
    Frq = Frq << 8;
    Work = RFM_Rd_Data (0x08);
    Frq = Frq | Work;
    Ind_Hex (235, 45, Frq, GREEN, BLACK);
    }
    }


    // Дальше прроверка, принял ли я пакет и индикация, но суть вопроса выше.


    // Read of the Receiver status.

    R_Stat = RFM_Rd_Data (0x12);
    Cnt++; // Это индикация ожидания.
    if ((Wait > 0) && (Cnt > 350))
    {
    Cnt = 0;
    Wait--;
    if ((Wait & 0x01) == 0x0)
    {
    LCD_DrawLine ((129 + i), 60, (129 + i), 48, 1, YELLOW);
    if (i < 100)
    {
    i++;
    }
    }
    }

    // Verify of the Stop conditions.

    if (Mode == 0)
    {
    Res_Progr (); // Не нажата ли кнопка хватит принимать?
    return (1);
    }
    } while (((R_Stat & 0x40) == 0x0) && (Wait > 0)); // Жду, пока не принят пакет или не истекло время ожидания.

    Res_Progr (); // Reset of the indication.
    if ((RFM_Rd_Data (0x12) & 0x40) == 0x40)
    {
    Rec_Cnt++; // Увеличиваю счётчик принятых пакетов.
    RFM_Wr_Data (0x12, 0xFF); // Принял пакет, Сбрасываю прерывания.
    return (0);
    }
    else
    {
    RFM_Wr_Data (0x12, 0xFF); // Не принял пакет, сбрасываю прерывания.
    return (1);
    }
    }


    Вопросы.
    В формулу подставлять Fxtal - в Гц или в КГц?
    Почему 2^24 - откуда это?
    Почему BW/500?
    Ну и самое главное, в чём я ошибаюсь, почему не происходит правильная корректировка частоты и приём?