problemen met NRF24l01 zender/ontvanger (pic16f73)

Beste allen,

Al enige tijd ben ik aan het stoeien met NRF24l01 chips. (Het gaat specifiek om de HF-NRF24L01-03 (€1,33) van Voti). Ik gebruik een 16f73 pic. De NRF is aangesloten op 3,3V, met een condensator. Ik heb verschillende codes van het internet gecombineerd met stukken van mijn eigen code.
Het schrijven en lezen van de registers van de NRF gaat prima, via SPI. Ik kan alle registers instellen en later teruglezen. Dat doet mij vermoeden dat de boel correct is aangesloten en dat de chip zou moeten werken.
Het gaat mis bij het verzenden en/of ontvangen van data, de payload. Dat werkt gewoon niet. Ik krijg in het statusregister (reg7) van de zender wel een interupt dat het aantal retries is bereikt, maar de interupt op de ontvanger doet helemaal niks.
Ik heb het volgende al gedaan.
- Zender en ontvanger op aparte voedingen
- Zender en ontvanger op verschillende afstanden van elkaar
- Registers zoveel mogelijk met rust laten en default instellingen gebruiken (in de code hieronder zijn veel stukken ‘comment’ gemaakt zodat ik het wel kon bewaren, maar niet zou compileren.
- Registers eigen en verschillende instellingen geven. Ik heb de channels, de frequentie, de pipes, allemaal een keer aangepast, allemaal hetzelfde resultaat.
- Op internet had ik gelezen bij iemand dat de chips alleen konden verzenden en ontvangen als ze op 5v aangesloten waren. De registers lezen en schrijven ging prima op 5v, ze gingen niet kapot, maar er werd ook niks ontvangen.
Ik denk dus dat er een fout zit in de code die opdrachten zou moeten verzenden en ontvangen, maar ik kom er niet achter wat het zou moeten zijn. Misschien (hopelijk) zie ik iets heel simpels over het hoofd.
Misschien dat ik de duurdere NRF24l01 chips moet bestellen, misschien werken die beter?

Ik heb de kopie van de code zo kort mogelijk gehouden, alles wat niet met verzenden/ontvangen te maken heeft heb ik weggelaten. De variabele ‘Opdracht[6]’ bevat de info van en naar de NRF. Ik heb een aparte code voor de zender en voor de ontvanger. De eerste regel geeft aan of deze chip een ontvanger of zender is. Het instellen van de NRF zit in een INCLUDE dat door beide gedeeld wordt. Sommige registers (reg1) zijn afhankelijk van de instelling zender of ontvanger.

Hopelijk is er iemand die me kan helpen.

Bedankt,

Benjamin

Code voor zender:

pic basic code:


; Zender

RxTx = 0                          ; Dit is de zendmodule (controller)

INCLUDE  "D:\PIC\NRF.inc"

Hoofdprogramma:

WHILE 1 = 1
IF Knop = Ingedrukt THEN 
 
     Opdracht[0] = NRF_Verzenden      ;Dit is de opdracht 'Payload' van de NRF, zie NRF symbolen
     Opdracht[1] = %01010101             ;Dit is de opdracht die ik wil verzenden

      AantalBytes = 1
      GOSUB Spi_NRF
      HIGH CE : DELAYUS 25 : LOW CE   ; Korte tijd de CE Pin hoog zodat de NRF weet dat hij moet verzenden
 

 WHILE 1 = 1                          ; In deze loop wordt het statusregister bekeken. 

 Opdracht[0] = NRF_NOP              ; Deze opdracht doet niks, maar geeft wel het statusregister terug.
 GOSUB Spi-NRF
 
 PRINT AT 1,1, BIN8 Opdracht[0]      ; Bit 4 wordt hoog als het maximale aantal retries bereikt is.
 
 IF KnopLinks = Ingedrukt THEN GOTO ClearInt     ; Als we het statusregister gelezen hebben kunnen we de interupts weer laag maken.
 WEND
 
 ClearInt:

     CLS
     Opdracht[0] = AdresClearInterupts 
     Opdracht[1] = ClearInterupts
    AantalBytes = 1
    GOSUB Spi_NRF

  ' flush all FIFO slots                ; Ook maken we de FIFO slots leeg.
     Opdracht[0] = FLUSH_TX
    AantalBytes = 1
    GOSUB Spi_NRF
    
ENDIF


WEND

Code voor ontvanger:

pic basic code:


; Ontvanger
RxTx = 1                       ; Dit is de ontvanger
INCLUDE  "D:\PIC\NRF.inc"

Hoofdprogramma:

WHILE 1 = 1
CE = 1                          ; CE moet hoog zijn om de NRF de lucht te laten scannen
 
  IF IRQ = 0 THEN            ; Als de Interuptlijn laag gaat dan is er data ontvangen.
    CE = 0                     ; CE moet laag om de registers te kunnen lezen
    Opdracht[0] = NRF_Ontvangen ; We geven de NRF de opdracht om de data uit de FIFO Slots in de byte 'Opdracht' te zetten
    Opdracht[1] = 1
 
    AantalBytes = 1
    GOSUB Spi_NRF

    PRINT AT 1,1, BIN8 Opdracht[1] ; De data wordt op het display getoond.

    Opdracht[0] = AdresClearInterupts   ; De interupts worden weer laag gemaakt
    Opdracht[1] = ClearInterupts
    AantalBytes = 1
    GOSUB Spi_NRF
   
  ' flush all FIFO slots 
    Opdracht[0] = FLUSH_RX          ; De FIFO slots worden leeggemaakt.
    AantalBytes = 0
    GOSUB Spi_NRF   
  ENDIF

WEND

Code voor het instellen van de NRF

pic basic code:


; NRF instellingen

; NRF Pinnen
SYMBOL CE = PORTC.6 
SYMBOL CSN = PORTC.7
SYMBOL Interupt = PORTB.7

;SCK is the serial clock for the SPI bus.
;When you configure your SPI bus, SCK should stay low normally (rising edges are
;active), and the clock samples data in the middle of data bits.

; SPI instellen
SYMBOL SPIInterupt = PIR1.3
SYMBOL SSPEN = SSPCON.5
SYMBOL CKP = SSPCON.4
SYMBOL RisingEdgesHigh = SSPSTAT.7
SYMBOL DataSample = SSPSTAT.6

'---[nRF command SET]------------------------ 
SYMBOL RegisterSchrijven = %00100000 ' Write Register command
SYMBOL RegisterLezen = %00000000 ' Read Register command
SYMBOL NRF_Ontvangen = %01100001 ' Read RX spi_array
SYMBOL NRF_Verzenden = %10100000 ' Write TX spi_array
SYMBOL FLUSH_TX = %11100001 ' Flush TX FIFO
SYMBOL FLUSH_RX = %11100010 ' Flush RX FIFO
SYMBOL AdresClearInterupts = RegisterSchrijven + 7
SYMBOL ClearInterupts = 0x70

SYMBOL R_RX_PL_WID = %01100000 ' read RX spi_array width for the top Rx spi_array in the FIFO
SYMBOL W_ACK_PAYLOAD = %10101000 ' RX mode: write spi_array to be transmitted with ACK packet mask for last 3 bits in range 000 - 101
SYMBOL W_TX_PAYLOAD_NOACK = %10110000 ' Disable auto ACK on the specific packet
SYMBOL NRF_NOP = %11111111 ' Reuse last sent spi_array

SPIInterupt = 0
CE = 0 ' clear CE until we start working
CSN = 1' unselect NRF slave otherwise it will never work

NRF_Instellen:

;----------SPI config--------:
SSPEN = 1                     ; SPI Enabled
CKP = 0                       ; SCK should stay LOW normally
DELAYMS 200
RisingEdgesHigh = 0           ; rising edges are active
DataSample = 1                ; clock samples DATA in the middle of DATA bits

    'REG 00 CONFIG
    Opdracht[0] = RegisterSchrijven
                                   ;76543210
    IF RxTx = 1 THEN opdracht[1] = %00001101
    IF RxTx = 0 THEN opdracht[1] = %00001100
    AantalBytes = 1
    GOSUB Spi_NRF
    DELAYMS 1
;7 x
;6 Mask interrupt caused by RX_DR  1: INTERRUPT NOT reflected ON the IRQ pin
;5 Mask interrupt caused by TX_DS  1: INTERRUPT NOT reflected ON the IRQ pin
;4 Mask interrupt caused by MAX_RT 1: Interrupt not reflected on the IRQ pin
;3 Enable CRC. Forced high if one of the bits in the EN_AA is high
;2 CRC encoding scheme '0' - 1 byte '1' – 2 bytes
;1 1: POWER UP, 0:POWER DOWN -> Deze moet hier nog uit staan, later in de setup wordt deze aangezet
;0 RX/TX control 1: PRX, 0: PTX


    'REG 01 EN_AA 
'    Opdracht[0] = RegisterSchrijven + 0x01
'                       ;76543210
'    Opdracht[1] =  %00000010
'    AantalBytes = 1
'    GOSUB Spi_NRF

;7  x
;6  x
;5  Enable auto ack. data pipe 5
;4  Enable auto ack. data pipe 4
;3  Enable auto ack. data pipe 3
;2  Enable auto ack. data pipe 2
;1  Enable auto ack. data pipe 1
;0  Enable auto ack. data pipe 0
    
    
    'REG 2 EN_RXADDR
'    Opdracht[0] = RegisterSchrijven + 0x02
'                       ;76543210
'    Opdracht[1] =  %00000010
'    AantalBytes = 1
'    GOSUB Spi_NRF
;7 x
;6 x
;5 Enable data pipe 5.
;4 Enable data pipe 4.
;3 Enable data pipe 3.
;2 Enable data pipe 2.
;1 Enable data pipe 1.
;0 Enable data pipe 0.    

    'REG 03 SETUP AW
'   Opdracht[0] = RegisterSchrijven + 3
'                       ;76543210
'   Opdracht[1] =  %00000011
'    AantalBytes = 1
'    GOSUB Spi_NRF

;7-2  x
;1  RX/TX Address field width
;0  RX/TX Address field width 11 = 5 Bytes

    'REG 04 SETUP PETR
'    Opdracht[0] = RegisterSchrijven + 0x04
'                      ;76543210
'    Opdracht[1] = 00011111
'    AantalBytes = 1
'    GOSUB Spi_NRF

;7 - 4 Auto Re-transmit Delay 0001   Wait 500uS
;3 - 0 Auto Retransmit Count ‘0011’ – Up to 3 Re-Transmit on fail of A


    'REG 05 RF_CH
'     Opdracht[0] = RegisterSchrijven + 0x05
'                      ;76543210
'     Opdracht[1] = 118
'    AantalBytes = 1
'    GOSUB Spi_NRF  
    ;7 x
;6 - 0 Sets the frequency channel nRF24L01 operates on  01000000


    'REG 6 RF_SETUP
'  Opdracht[0] = RegisterSchrijven + 0x06
'                  ;76543210
'    Opdracht[1] = %00001110
'    AantalBytes = 1
'    GOSUB Spi_NRF

;7 - 4 xxxx
;3 - Air Data Rate ‘0’ – 1Mbps ‘1’ – 2Mbps
;2 - 1 Set RF output power in TX mode    '00' – -18dBm  '01' – -12dBm '10' – -6dBm    '11' – 0dBm
;0 Setup LNA gain      


  
    'REG 07 STATUS 
    Opdracht[0] = AdresClearInterupts 
    Opdracht[1] = ClearInterupts
    AantalBytes = 1
    GOSUB Spi_NRF

;7 x
;6 Data Ready RX FIFO interrupt. Asserted when new data arrives RX FIFOb. 
;5 Data Sent TX FIFO interrupt. Asserted when packet transmitted on TX. Write 1 TO CLEAR BIT.
;4 Maximum number of TX retransmits interrupt Write 1 to clear bit. If MAX_RT is asserted it must be cleared to enable further communication.
;3 - 1 Data pipe number for the payload available for reading from RX_FIFO 000-101: Data Pipe Number 110: Not Used 111: RX FIFO Empty
;0 TX FIFO full flag. 1: TX FIFO full. 0: Available locations in TX FIFO.
    
        
; REG 0A 'RX address pipe0' register address 
'     Opdracht[0] = RegisterSchrijven + 0x0A
'                      ;76543210
'     Opdracht[1] = 0xE7
'     Opdracht[2] = 0xE7
'     Opdracht[3] = 0xE7
'     Opdracht[4] = 0xE7
'     Opdracht[5] = 0xE7
'    AantalBytes = 5
'    GOSUB Spi_NRF    
    

 
'; REG 10 TX_ADDR    
'     Opdracht[0] = RegisterSchrijven + 0x10
'                      ;76543210
'     Opdracht[1] = 0xE7
'     Opdracht[2] = 0xE7
'     Opdracht[3] = 0xE7
'     Opdracht[4] = 0xE7
'     Opdracht[5] = 0xE7
'    AantalBytes = 5
'    GOSUB Spi_NRF

'REG 11 RX_PW_P0 - nr of bytes in rx payload
     Opdracht[0] = RegisterSchrijven + 0x11
                      ;76543210
     Opdracht[1] = 1
   AantalBytes = 1
    GOSUB Spi_NRF 

'REG 12 RX_PW_P0 - nr of bytes in rx payload
     Opdracht[0] = RegisterSchrijven + 0x12
                      ;76543210
     Opdracht[1] = 1
   AantalBytes = 1
    GOSUB Spi_NRF 
  

    'NRF Aanzetten (bit 1 wordt hoogegaakt)
    Opdracht[0] = RegisterSchrijven
                                   ;76543210   
    IF RxTx = 1 THEN opdracht[1] = %00001111
    IF RxTx = 0 THEN opdracht[1] = %00001110
    AantalBytes = 1
    GOSUB Spi_NRF
    DELAYMS 3
    

;7 x
;6 Mask interrupt caused by RX_DR  0: Reflect RX_DR as active low interrupt on the IRQ pin
;5 Mask interrupt caused by TX_DS  1: INTERRUPT NOT reflected ON the IRQ pin
;4 Mask interrupt caused by MAX_RT 1: Interrupt not reflected on the IRQ pin
;3 Enable CRC. Forced high if one of the bits in the EN_AA is high
;2 CRC encoding scheme '0' - 1 byte '1' – 2 bytes
;1 1: POWER UP, 0:POWER DOWN
;0 RX/TX control 1: PRX, 0: PTX



    

  ' flush all FIFO slots 
    Opdracht[0] = FLUSH_TX
    GOSUB Spi_NRF
    
    Opdracht[0] = FLUSH_RX
    GOSUB Spi_NRF  
    GOTO Hoofdprogramma

Code voor subroutine communicatie met SPI en NRF

pic basic code:


Spi_NRF:

CSN = 0                        ; ChipSelectNot - Active low lijn om NRF te laten weten dat er iets gaat gebeuren
ByteNr = 0                     ; Teller van aantal bytes dat over spi naar NRF gaat op 0 zetten
DELAYMS 1
      
  REPEAT 
  SSPBUF = Opdracht[ByteNr]    ; Zet opdrachten in SPI buffer

    WHILE SPIInterupt = 0 : WEND ; Wacht even totdat de SPI interupt aangeeft klaar te zijn
      SPIInterupt = 0            ; Spi flag weer laag maken
     DELAYMS 1
            Opdracht[ByteNr] = SSPBUF   ; Nu de teruggegeven byte weer in opdracht zetten zodat we die kunnen lezen
  INC ByteNr                            
  UNTIL ByteNr > AantalBytes      
  
CSN = 1                         ; Unselect de NRF weer tot de volgende actie
    RETURN

Goede SPI mode? (er zijn er 4)

Arco - "Simplicity is a prerequisite for reliability" - hard en software ontwikkeling: www.arcovox.com

Beste Arco,

Dankje, ik heb wat verschillende instellingen geprobeerd, maar alleen met deze instellingen kan ik communiceren met de registers. Ik heb niet alle vier de modes geprobeerd, dus dat zal ik eens doen.

Dankje, ik laat het weten.

Als je de registers terug kan lezen kun je er wel vanuit gaan dat de hardware en spi settings goed zijn.
Ik heb het een tijdje (10 jaar) geleden wel eens uitgezocht en in Bascom geprogrammeerd en werkend gekregen.
https://www.mcselec.com/index.php?option=com_content&task=view&amp…

Kijk eens naar de Setup_rx en Setup_Tx subs om te vergelijken welke registers ik set.

Andere SPI modes hebben inderdaad geen zin. Ook ik aan de hand van de subs gekeken naar welke settings werken, ook dat maakt geen verschil.

Ik zie wel dat ik de CSN pin bedien binnen de SPI_NRF subroutine en dat jij dat doet bij elke afzonderlijke communicatie met de registers (vlak voor en vlak na de jump naar de subroutine). Ik kan me niet voorstellen dat dat bij een Payload echt een probleem zou zijn, aangezien het op hetzelfde neerkomt. Het is echter wel een verschil, dus vandaar dat ik het noem. Wat denken jullie?

Het hangt van de slave af. Sommigen vinden het prima dat je /SS laag maakt, alles verstuurt, en weer hoog maakt.
Andere moeten expliciet voor en na ieder compleet commando laag resp. hoog gemaakt worden...

Arco - "Simplicity is a prerequisite for reliability" - hard en software ontwikkeling: www.arcovox.com
Jochem

Golden Member

Schema kan ook helpen (en layout).
edit: sorry ik zie dat je het over een module hebt, dan zal het schema en layout getest en in orde zijn.

En een foto van de opstelling.

Die dingen moeten het overigens prima doen op 3.3V.

Is je voeding stabiel genoeg en kan hij de pieken aan die zo'n zender veroorzaakt? Eventueel de module nog wat upgraden met een paar keramische (SMD) C'tjes over de voedingspinnen van de connector. (Met een foto van de opstelling is beter te beoordelen of je misschien veel lange draden gebruikt.)

[Bericht gewijzigd door Jochem op 9 mei 2017 21:00:50 (25%)]

Heb geduld: alle dingen zijn moeilijk voordat ze gemakkelijk worden.

Op 9 mei 2017 18:01:43 schreef benjamin.lentjes:
Ik zie wel dat ik de CSN pin bedien binnen de SPI_NRF subroutine en dat jij dat doet bij elke afzonderlijke communicatie met de registers (vlak voor en vlak na de jump naar de subroutine). Ik kan me niet voorstellen dat dat bij een Payload echt een probleem zou zijn, aangezien het op hetzelfde neerkomt. Het is echter wel een verschil, dus vandaar dat ik het noem. Wat denken jullie?

Pagina 45 van de datasheet:
The SPI commands are shown in Table 16.. Every new command must be started by a high to low transition
on CSN.

Ik kan niet uit jou code opmaken hou je de opdracht array vult, maar zodra je een andere commando aanspreekt moet je de CSN pin hoog laag maken.
Payload vullen of leeg halen is 1 commmando met 1~32 bytes erachteraan.
Dus CSN laag, Payload commando, 1~32 bytes , CSN hoog.

Het werkt!

Kortere kabels en een extra c'tje was de oplossing. Overigens gebruik ik nu de +versie van de module, die was toch in de aanbieding bij bitsandparts.eu. Dan is die extra condensator niet eens nodig.

Voor de volledigheid hier de delen code die de opdracht moet verzenden. Ik zend steeds maar één byte aan data, dat is voor de controller die ik ga maken voldoende.

Bedankt allemaal :)

pic basic code:



SYMBOL NRF_Verzenden = %10100000 ' Write TX spi_array
DIM Opdracht[6] as byte

IF Knop = Ingedrukt THEN 
 
     Opdracht[0] = NRF_Verzenden      ;Dit is de opdracht 'Payload' van de NRF, zie NRF symbolen
     Opdracht[1] = %01010101             ;Dit is de opdracht die ik wil verzenden
 
      AantalBytes = 1
      GOSUB Spi_NRF
      HIGH CE : DELAYUS 25 : LOW CE   ; Korte tijd de CE Pin hoog zodat de NRF weet dat hij moet verzenden
 

; Subroutine
Spi_NRF:

CSN = 0                        ; ChipSelectNot - Active low lijn om NRF te laten weten dat er iets gaat gebeuren
ByteNr = 0                     ; Teller van aantal bytes dat over spi naar NRF gaat op 0 zetten
DELAYMS 1
 
  REPEAT 
  SSPBUF = Opdracht[ByteNr]    ; Zet opdrachten in SPI buffer
 
    WHILE SPIInterupt = 0 : WEND ; Wacht even totdat de SPI interupt aangeeft klaar te zijn
      SPIInterupt = 0            ; Spi flag weer laag maken
     DELAYMS 1
            Opdracht[ByteNr] = SSPBUF   ; Nu de teruggegeven byte weer in opdracht zetten zodat we die kunnen lezen
  INC ByteNr                            
  UNTIL ByteNr > AantalBytes      
 
CSN = 1                         ; Unselect de NRF weer tot de volgende actie
    RETURN