Обсуждаем цифровые устройства...
Ответить

Как правильно принимать данные у NRF24L01

Вт янв 15, 2019 12:10:58

Если есть знатоки данного изделия, подскажите как с ним правильно работать, уже всю голову сломал. Ну вот собственно есть такой код:
status = NRF24_ReadReg(STATUS); //1

if(status & 0x40) {
NRF24_Read_Buf(RD_RX_PLOAD, RX_BUF, TX_PLOAD_WIDTH);
NRF24_WriteReg(STATUS, 0x40); //2


Выполняет он прием данных, т е считывает регистр статуса, если там выставлен флаг прихода данных, читаем данные, и переписывает регистр статуса с сброшенными битами приема. В чем тут проблема - если приходит новый пакет между точками 1 и 2, мы об этом факте не узнаем, так как регистр статуса уже прочитан, после чего пришел новый пакет, и мы на позиции 2 инфу об этом факте затираем. Данная проблема не проявляет себя при низких скоростях, но вот как только к данные начинают идти подряд от значительно более быстрого устройства, она происходит регулярно. При этом насколько я понимаю, ножка IRQ сбрасывается именно при изменении регистра статуса. Т е один фиг, что через прерывание работать, что через статус, все равно эта ситуация будет иметь место быть. Посмотрел код либы на ардуино, там то же самое сделано. Как собственно правильно принимать данные от этой железяки?

Re: Как правильно принимать данные у NRF24L01

Вт янв 15, 2019 21:55:28

Нужно изучать работу с регистром FIFO STATUS (0x17).

Сам сейчас мучаю эти модули, но до FIFO буфера не добрался

Стало самому интересно в этой теме.

Код:
  uint8_t status, fifo_before, fifo_after;

  status = NRF24_ReadReg(STATUS);//STATUS
  if(status & RX_DR)
  {
    fifo_before = NRF24_ReadReg(FIFO_STATUS);//FIFO_STATUS
    NRF24_Read_Buf(RD_RX_PLOAD,RX_BUF,TX_PLOAD_WIDTH);
    fifo_after = NRF24_ReadReg(FIFO_STATUS);//FIFO_STATUS
   
    printf("\n\rFIFO STATUS BEFORE: %d, FIFO STATUS AFTER: %d\n\r", fifo_before, fifo_after);
  }


выводит в терминал
FIFO STATUS BEFORE: 16, FIFO STATUS AFTER: 17


| RES | TX_REUSE | TX_FULL | TX_EMPTY | RES | RX_FULL | RX_EMPTY |
16 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
17 | 0 | 0 | 0 | 1 | 0 | 0 | 1 |


следовательно, до чтения PAYLOAD флаг RX_EMPTY в регистре FIFO_STATUS установлен в "0" что означает, что в буфере FIFO есть данные, после чтения PAYLOAD флаг RX_EMPTY устанавливается в "1" - буфер пуст. Флаг RX_FULL находится в "0". я буфер не переполняю. Проверил возможность переполнения буфера - все отрабатывает как и описано в ДШ - устанавливается флаг RX_FULL .

Как дальше с этим жить я ХЗ. Максимально поднять скорость SPI NRF24l01 и перед сбросом флага
Код:
NRF24_WriteReg(STATUS, 0x40);
проверить бит RX_EMPTY на наличие несчитанных данных

Re: Как правильно принимать данные у NRF24L01

Ср янв 16, 2019 11:18:50

Ну в общем решил я проблему. Она оказалась сдвоенным косяком. Самым главным был косяк с тем, что как оказалось мьютексы во FreeRTOS при захвате в узких циклах из потоков в одинаковым приоритетом могут приводить к удушению одного из потоков :shock: . Это для меня, человека привыкшего к прелестям pthreads оказалось просто удивительно жутким фактом. Ну собственно происходило удушение одного из потоков на линии обработки данных, и получалась иллюзия того, что пакет один периодически не доходил. Но все же косяк с недоходом пакета из-за высокой скорости передатчика происходил, намного реже, но все же. После перелопачивания кучи чужого кода, пришел вот к такой конструкции.
Код:
bool NRF24_available() {
    uint8_t fs = NRF24_ReadReg(FIFO_STATUS);
    if (!(fs & _BV(0)))
       return true;

    return false;
}

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

int NRF24_Receive(uint8_t *payload)
{
   NRF24_Read_Buf(RD_RX_PLOAD, RX_BUF, TX_PLOAD_WIDTH);
   uint8_t status = NRF24_ReadReg(STATUS);
   NRF24_WriteReg(STATUS, status | 0x70);
   memcpy(payload, RX_BUF, TX_PLOAD_WIDTH);

   return TX_PLOAD_WIDTH;
}

Т е сначала проверяем есть ли данные, а потом читаем. После этого, все стало работать как хорошо отлаженные часы.
Ответить