Forum: Mikrocontroller und Digitale Elektronik nRF24L01+ Funkmodul - Auto Acknowledgement sendet keine Payload


von Ralph K. (rosti_mcn)


Lesenswert?

Hallo,
1
neue_Hardware ? call_mikrocontroller_net() : okay;  // :D

Zwei nRF24L01+ sollen bidirektional miteinander kommunizieren, einer 
davon als PTX der andere als PRX. In der Richtung PTX->PRX funktioniert 
alles wie es soll. Aber bei Acknowledge-Payloads habe ich noch ein 
Problem zwischen den Ohren:

Wenn ich per W_ACK_PAYLOAD
1
#define nRF_CMD_W_ACK_PAYLOAD          0x98    // Write Payload to be transmitted together with ACK packet on pipe PPP

Daten schreibe, z.B. so:
1
lib_nRF24L01_write_ack_data( "ANTWORT", 8, 1);  // §§§ only a test case

, wobei
1
// Write data to TX-FIFO as acknowledge payload.
2
// Returns false, when all FIFOs are in use already.
3
uint8_t lib_nRF24L01_write_ack_data( void * data, uint8_t len, uint8_t pipe_num)
4
{
5
  if ( lib_nRF24L01_TX_FIFO_is_full() )      // check for free FIFO
6
  {
7
#ifdef DEBUG_ACK
8
    // flash LED
9
    MEDIUM_LED_FLASH( 1);
10
    SHORT_LED_FLASH( 4);
11
#endif
12
    return false;                // §§ maybe there could be done more serious action taken here (e.g. flushing FIFOs)
13
  }
14
  else
15
  {
16
#ifdef DEBUG_ACK
17
    // flash LED
18
    MEDIUM_LED_FLASH( 1);
19
    SHORT_LED_FLASH( 1);
20
#endif
21
    lib_nRF24L01_EXECUTE(
22
      spi_transmit_byte( nRF_CMD_W_ACK_PAYLOAD | pipe_num );
23
      spi_transmit_data( data, len);
24
    )
25
  }
26
  return true;
27
}

ist, kommt bei dem PTX zwar ein Acknowledgement an, aber keine Payload. 
Das LED-Geblinker sagt mir außerdem, dass der PRX auch gar keine Payload 
versendet hat (zumindest erzeugt er keinen TX_DS-IRQ, was er laut Manual 
m.E. dann aber tun sollte).

Es hat sich dann herausgestellt, dass ich mehr als 3 Ack-Payloads 
schreiben kann, ohne dass dabei ein Fehler (TX-FIFO full, siehe letzter 
Code-Abschnitt) auftaucht:
1
while ( 1 )
2
{          
3
  lib_nRF24L01_write_ack_data( "ANTWORT", 8, 1);  // §§§ only a test case
4
}

Ich initialisiere den nRF24L01+ wie folgt:
1
// Initialises nRF24L01+ registers with default values and puts it into power down state.
2
// Note: this function can also be used to reset the nRF24L01+.
3
// Parameters:
4
//    mode    lib_nRF24L01_TXmode | lib_nRF24L01_RXmode
5
//     groupID   the middle byte of the address of the nRF24L01+. This lib uses this byte as common address part of a multiceiver-group.
6
//     deviceID   the LSByte of the address of the nRF24L01+. This lib uses default values from 1...6 for the transmitters of a multiceiver-group.
7
//     rf_channel  RF frequency channel to use: F(RF) = 2400 + x [MHz], where x = 0..125
8
void lib_nRF24L01_init_nRF24L01( uint8_t mode, uint8_t groupID, uint8_t deviceID, uint8_t rf_channel)
9
{
10
  // the nRF24L01+ power on reset procedure needs 100ms after operating voltage is supplied
11
  if ( ! (currentState & STATE_BITMASK_INIT  ) )
12
    _delay_us( nRF24L01_DELAY_POWERON_RESET);
13
14
  if (   (currentState & STATE_BITMASK_PWR_UP) )
15
  {
16
    // flush all data pipes, reset all interrupt flags (IRQ-pin), then go down
17
    lib_nRF24L01_flush_TX_FIFO();
18
    lib_nRF24L01_flush_RX_FIFO();
19
    lib_nRF24L01_clear_IRQ( nRF_REGBITMASK_STATUS_TX_DS);
20
    lib_nRF24L01_clear_IRQ( nRF_REGBITMASK_STATUS_RX_DR);
21
    lib_nRF24L01_clear_IRQ( nRF_REGBITMASK_STATUS_MAX_RT);
22
    lib_nRF24L01_power_down();
23
  }
24
25
  // Set RF channel
26
  lib_nRF24L01_set_regbyte( nRF_REG_RF_CH, rf_channel);
27
  // Set data speed & Output Power as preconfigured in lib_nRF24L01_RF_SETUP (set in lib_nRF24L01.h)
28
  lib_nRF24L01_set_regbyte( nRF_REG_RF_SETUP, lib_nRF24L01_RF_SETUP);
29
30
  // Set Device Address Width
31
  lib_nRF24L01_set_regbyte( nRF_REG_SETUP_AW, nRF_REGBITVAL_SETUP_AW_3BYTES);
32
  
33
  // Set device addresses for a "multiceiver group" (a star topology consisting of 1 receiver and up to 6 transmitters) with auto acknowledge
34
  if ( mode == lib_nRF24L01_TXmode )
35
  {
36
    // Set Device Address (which identifies the transmitter)
37
    lib_nRF24L01_set_tx_addr( groupID, deviceID);
38
    // Enable only RX data pipe 0 for receiving data (to receive acknowledge-packets from a listening receiver)
39
    lib_nRF24L01_set_regbyte( nRF_REG_EN_RXADDR, nRF_REGBITMASK_EN_RXADDR_ERX_P0);
40
    // addresses to listen to
41
    lib_nRF24L01_set_rx_addr( 0, groupID, deviceID);  // Note: when using auto acknowledgement, RX pipe 0 of a nRF24L01+ in TX-mode has to be set to the own device address
42
    // just for tidiness: write unused (§ thats just my personal convention!) addresses to all unsed data pipes
43
    lib_nRF24L01_set_rx_addr( 1, 0xFF, 0xFF);
44
    lib_nRF24L01_set_rx_addr( 2, 0xFF, 0xFF);
45
    lib_nRF24L01_set_rx_addr( 3, 0xFF, 0xFF);
46
    lib_nRF24L01_set_rx_addr( 4, 0xFF, 0xFF);
47
    lib_nRF24L01_set_rx_addr( 5, 0xFF, 0xFF);
48
  }
49
  else  // i.e. mode == lib_nRF24L01_RXmode (multiceiver)
50
  {
51
    // In order to avoid address conflicts which could occur when the PRX is switched to TX mode on the fly,
52
    // the Device Address is set even in RX-mode
53
    lib_nRF24L01_set_tx_addr(    groupID, deviceID > 6 ? deviceID : 0);    // ensure the deviceID does not collide with one of the transmitters of the same group
54
    // Enable all RX data pipe addresses for receiving data
55
    lib_nRF24L01_set_regbyte( nRF_REG_EN_RXADDR, nRF_REGBITMASK_EN_RXADDR_ERX_ALL);
56
    // addresses to listen to
57
    lib_nRF24L01_set_rx_addr( 0, groupID, 1);
58
    lib_nRF24L01_set_rx_addr( 1, groupID, 2);
59
    lib_nRF24L01_set_rx_addr( 2, groupID, 3);
60
    lib_nRF24L01_set_rx_addr( 3, groupID, 4);
61
    lib_nRF24L01_set_rx_addr( 4, groupID, 5);
62
    lib_nRF24L01_set_rx_addr( 5, groupID, 6);
63
  }
64
  
65
  // Enable the nice "Enhanced ShockBurst" features:
66
  // ... Automatic Retransmission
67
  //     Note 1: use nRF_REG_SETUP_RETR ARD setting faster than 500us with caution: read note (d) at the end of the Register Map Table (page 60 of manual)!
68
  //     Note 2: § in order to avoid repeated transmission collisions, ensure different values for each device working on the same RF-channel
69
  if ( mode == lib_nRF24L01_TXmode )
70
  {
71
    uint8_t delay = (0x10 * (1+deviceID)) & nRF_REGBITMASK_SETUP_RETR_ARD;  // see nRF_REGVAL_SETUP_RETR_ARD_*-constants
72
    lib_nRF24L01_set_regbyte( nRF_REG_SETUP_RETR, (delay | nRF_REGVAL_SETUP_RETR_ARC_15) );
73
  }
74
  else
75
  {
76
    lib_nRF24L01_set_regbyte( nRF_REG_SETUP_RETR, (nRF_REGVAL_SETUP_RETR_ARD_500 | nRF_REGVAL_SETUP_RETR_ARC_15) );
77
  }
78
  // ... Dynamic Payload Length as well as Automatic Acknowledgement Payloads
79
  lib_nRF24L01_set_regbyte( nRF_REG_FEATURE,   nRF_REGBITMASK_FEATURE_EN_DPL      // enables Dynamic Payload Length
80
                         | nRF_REGBITMASK_FEATURE_EN_DYN_ACK    // enables use of nRF_CMD_W_TX_PAYLOAD_NOACK command
81
                         | nRF_REGBITMASK_FEATURE_EN_ACK_PAY    // enables "Acknowledge Payloads"
82
              );
83
  // ... enable Automatic Acknowledgement for all data pipes
84
  lib_nRF24L01_set_regbyte( nRF_REG_EN_AA, nRF_REGBITMASK_EN_AA_ENAA_ALL);
85
  // ... enable Dynamic Payload Length for all data pipes
86
  lib_nRF24L01_set_regbyte( nRF_REG_DYNPD, nRF_REGBITMASK_DYNPD_ALL);
87
88
  currentState = STATE_BITMASK_INIT;                      // initialised, powered down
89
}

Sorry, dass ich hier nichts zusammengekürzt habe. Hoffe ihr seid mir 
nicht böse ;)
Das Ergebnis ist (abgesehen von Adressen und so, der Dump stammt von 
einem Modul einer anderen "Gruppe"):
1
Register 0 =    0000 1111   CONFIG      _MMM --PR   Mask interrupt(3), Power, RX-mode
2
Register 1 =    0011 1111   EN_AA       __PP PPPP   Pipe number
3
Register 2 =    0011 1111   EN_RXADDR   __PP PPPP   Pipe number
4
Register 3 =    0000 0001   SETUP_AW    ____ __AW   Address Width(2)
5
Register 4 =    0001 1111   SETUP_RETR  ---- ----   RETR delay, RETR max
6
Register 5 =    0010 1010   RF_CH       _CCC CCCC   Channel
7
Register 6 =    0010 0000   RF_SETUP    -_LP HPP_   Low speed, PLL Lock, High speed, Power(2)
8
Register 7 =    0000 1110   STATUS      _III NNNT   Interrupt flag, Number of data pipe for top-most RX-fifo data (3), TX-fifo full
9
Register 8 =    0000 0000   OBSERVE_TX  LLLL RRRR   Lost packets (4), Retransmitted Packets (4)
10
Register 9 =    0000 0000   RPD         ____ ___R   Received Power (on/off)
11
Register 10 =   0000 0001   RX_ADDR_P0              3 Bytes, LSByte first
12
Register 11 =   0000 0010   RX_ADDR_P1              3 Bytes, LSByte first
13
Register 12 =   0100 0010   RX_ADDR_P2              LSB
14
Register 13 =   0100 0010   RX_ADDR_P3              LSB
15
Register 14 =   0100 0010   RX_ADDR_P4              LSB
16
Register 15 =   0100 0010   RX_ADDR_P5              LSB
17
Register 16 =   0000 0000   TX_ADDR                 3 Bytes, LSByte first
18
Register 17 =   0000 0000   RX_PW_P0    __NN NNNN   Number of Bytes in RX data pipe 0
19
Register 18 =   0000 0000   RX_PW_P1    __NN NNNN   Number of Bytes in RX data pipe 1
20
Register 19 =   0000 0000   RX_PW_P2    __NN NNNN   Number of Bytes in RX data pipe 2
21
Register 20 =   0000 0000   RX_PW_P3    __NN NNNN   Number of Bytes in RX data pipe 3
22
Register 21 =   0000 0000   RX_PW_P4    __NN NNNN   Number of Bytes in RX data pipe 4
23
Register 22 =   0000 0000   RX_PW_P5    __NN NNNN   Number of Bytes in RX data pipe 5
24
Register 23 =   0001 0001   FIFO_STATUS _RFE __FE   Transmitter Reuse, Full, Empty __ Receiver Full, Empty
25
Register 28 =   0011 1111   DYNPD       __PP PPPP   Pipes 
26
Register 29 =   0000 0111   FEATURE     ____ _DPN   enable Dyn payload, enable Payload with ack, enable Noack-cmd

Langer Rede kurzer Sinn: sieht oder ahnt jemand die Wurzel des Übels?

Bin für jeden Hinweis zur Ergreifung des Täters dankbar :)

Ralph

von Ralph K. (rosti_mcn)


Lesenswert?

Habe mir gerade den Code von maniacbug angesehen. Was mir dort auffällt, 
ist folgender Code:
1
void RF24::toggle_features(void)
2
{
3
  csn(LOW);
4
  SPI.transfer( ACTIVATE );
5
  SPI.transfer( 0x73 );
6
  csn(HIGH);
7
}
8
9
10
void RF24::enableDynamicPayloads(void)
11
{
12
  // Enable dynamic payload throughout the system
13
  write_register(FEATURE,read_register(FEATURE) | _BV(EN_DPL) );
14
15
  // If it didn't work, the features are not enabled
16
  if ( ! read_register(FEATURE) )
17
  {
18
    // So enable them and try again
19
    toggle_features();
20
    write_register(FEATURE,read_register(FEATURE) | _BV(EN_DPL) );
21
  }
22
  ...
23
}

Was hat es damit denn auf sich? Ist das Kommando ACTIVATE (0x50) ein 
undokumentiertes "Feature" des nRF24L01+???

von Andreas G. (beastyk)


Lesenswert?

Moin Ralph,

ich hab mir deinen Thread mal so angesehen, weil ich auch 2 Module 
bestellt hab und mich das Ansteuern der Chips interessiert.
Ich denk mal das niemand etwas mit den Codeschnippseln anfangen kann, 
weil du dich bei dem Ganzen auf Defines berufst die wir nicht kennen, 
bzw. welche Lib hast du da in der Mangel? Kennst du die von Elia? 
(https://github.com/Torrentula/NRF-wireless)
Benutzt Maniacbug die gleiche "Lib" oder hat der ne ganz andere...*Kugel 
putz*

Muß man in einer Config vielleicht hinterlegen wie groß der Payload ist 
der ankommt?

Tut mir leid wenn ich jetzt keine Hilfe war, wollte dich aber auch nich 
so sitzen lassen :o)

Gruß
dat
Beast

von Ralph K. (rosti_mcn)


Angehängte Dateien:

Lesenswert?

Danke liebes Beast, bekommst ein Karma++ :)

Hast schon Recht mit den "Code-Schnipseln". Ich häng hier mal die 
komplette Lib zur Ansicht ran. Wobei ich zwar nicht davon ausgehe, dass 
der Fehler in einer der cpp-Konstanten-Definitionen liegt, aber man weiß 
ja nie.
Dein Hinweis auf die Größe der Payload trifft leider nicht, weil das 
"Auto Ack With Payload" die Konfiguration von dynamischen Payload-Width 
voraussetzt. Sprich: der nRF24 macht die Arbeit selbst.

Zum aktuellen Stand des Problems:
 * das von maniacbug verwendete Kommando ACTIVATE ist vermutlich der 
alten Version des nRF24 geschuldet (der ohne "+"),
 * vorsichtshalber prüfe ich jetzt den Wert des FEATURE-Registers nach 
dem Setzen, da kann der Fehler also nicht liegen.

Zentrale Frage ist für mich immer noch: wieso kann ich (bei ruhendem 
Funkverkehr) mehr als 3 Ack-Payloads schreiben, ohne dass der TX-FIFO 
voll ist?

Da ist was faul im Staate Embeddi!

Grüße
Ralph

: Bearbeitet durch User
von Ralph K. (rosti_mcn)


Lesenswert?

Erledigt.

Fehler war doch in der Tat "nur" eine falsche Konstante.
Da muss man erst mal drauf kommen :(

Korrekt ist:
1
#define nRF_CMD_W_ACK_PAYLOAD          0xA8    // Write Payload to be transmitted together with ACK packet on pipe PPP

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.