Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 11 of 11

Thread: Code just slightly too slow to wirelessly stream audio via Nrf24L01+?

  1. #1
    Junior Member
    Join Date
    Oct 2019
    Posts
    9

    Code just slightly too slow to wirelessly stream audio via Nrf24L01+?

    Hello,

    I tried to make a wireless live mono audio link with a Teensy 3.2 as a transmitter and Teensy 4.0 as a receiver.
    Mainly copied a code example I found somewhere in the forum and changed it slightly.. Want to stream audio from a mic + several times a secound data from a Joystick on a different pipe but the same channel.
    Everything seems to work fine but there is still a little "popping" sound several times a secound.
    Without the joystick data there is no problem. Any Ideas, how to get it working/ make the code faster?
    Another strange observation I made is that it only works at specific CPU Speeds: Teensy 3.2@120MHz and Teensy 4.0@24MHz. Anything else, even higher, produces extreme jitter. Logically, a higher speed should bring higher performance, I thought?

    Here is the code for the Teensy 3.2 (transmitter):

    Code:
    //Teensy 3.2 @ 120Mhz - transmitter
    
    #include <Audio.h>
    #include <SPI.h>
    #include <nRF24L01.h>
    #include <RF24.h>
    
    #define audiobuffersize 128 // one block in audio library has 128 values of 2 byte
    
    #define JoyX_Pin 16
    #define JoyY_Pin 17
    #define JoySwitch_Pin 18
    
    uint16_t JoyX;
    uint16_t JoyY;
    bool JoySwitch;
    byte ControlBuffer[8];
    
    RF24 radio(20,21); // Teensy 3.6 pin 21=CE, Teensy 3.6 pin 15=CSN
    
    const byte pipeaddress[2][5] = {
        {'1','N','O','D','E'},
        {'2','N','O','D','E'}
    };
    
    elapsedMillis millisec;
    
    // GUItool: begin automatically generated code
    // defs for audio library
    AudioInputI2S i2s1;
    AudioOutputI2S i2s2;
    AudioRecordQueue queue1;
    AudioSynthWaveformSine sine1;
    AudioConnection patchCord1(i2s1, queue1);
    
    AudioControlSGTL5000 sgtl5000_1;
    // GUItool: end automatically generated code
    
    uint8_t bufr[audiobuffersize * 2]; //buffer to hold 256 byte of audio data
    
    void setup()
    {
    //Serial.begin(9600);
    //Serial.println("Start Transmitter");
    
    
    AudioMemory(100); //give the Audio Library some memory to work with
    
    Serial.begin(36000);
    
    // use alternate SPI pins for nrf24
    SPI.setMOSI(7);
    SPI.setMISO(8);
    SPI.setSCK(14);
    SPI.begin();
    
    // Setup the SGTL5000 AIC
    //sgtl5000_1.enable(); //activate AIC
    
    sgtl5000_1.enable(); //Enable the SGTL5000
    //sgtl5000_1.volume(0.4);
    
    
    delay(100);
    
    radio.begin();
    //radio.setPayloadSize(32); //this is the maximum payload size for a packet transfer of nrf24
    radio.setAutoAck(false); // no Ack
    //radio.enableDynamicPayloads();
    //radio.setRetries(0,0);
    radio.disableCRC(); // no CRC
    radio.setPALevel(RF24_PA_MAX);
    radio.setDataRate(RF24_2MBPS);
    radio.setChannel(121);
    delay(50);
    
    radio.openWritingPipe(pipeaddress[0]);
    radio.stopListening(); // switch to transmit mode
    delay(100);
    
    queue1.begin();
    }
    
    void loop()
    {
      
      if(millisec>=100){
      JoyX=analogRead(JoyX_Pin);
    Serial.print("Position X: ");
    Serial.print(JoyX);
    
    JoyY=analogRead(JoyY_Pin);
    Serial.print("          Position Y: ");
    Serial.print(JoyY);
    
    
    Serial.print("    SW: ");
    Serial.println(JoySwitch);
    
    
    if(analogRead(JoySwitch_Pin)<=50){
     JoySwitch=true; 
    }
    else{
      JoySwitch=false;
    }
    
    ControlBuffer[0]=JoyX;
    ControlBuffer[4]=JoyY;
    ControlBuffer[7]=JoySwitch;
    
    delayMicroseconds(5);
    radio.openWritingPipe(pipeaddress[0]);
    radio.write(&ControlBuffer,8);
    millisec=0;
    
      }
    
      
    if (queue1.available())
    {
    
    memcpy(bufr, queue1.readBuffer(), audiobuffersize*2); // copy 256 byte audio data from audio library buffer to bufr
    queue1.freeBuffer();
    
    delayMicroseconds(5);
    radio.openWritingPipe(pipeaddress[1]);
    // send audio data in 8 packages a 32 byte to the FIFO buffers
    for (int i=0; i<8; i++)
    {
    radio.writeFast(&bufr[i * 32],32);
    }
    }
    }
    And here for the Teensy 4.0 (receiver):

    Code:
    //Teensy 4.0@24 MHz (receiver)
    
    #include <Audio.h>
    #include <SPI.h>
    #include <nRF24L01.h>
    #include <RF24.h>
    
    #define audiobuffersize 128 // one block in audio library has 128 values of 2 byte
    
    RF24 radio(14,15); // Teensy 3.6 pin 21=CE, Teensy 3.6 pin 15=CSN
    
    const byte pipeaddress[2][5] = {
        {'1','N','O','D','E'},
        {'2','N','O','D','E'}
    };
    
    // GUItool: begin automatically generated code
    // defs for audio library
    AudioPlayQueue queue1;
    AudioOutputI2S i2s1;
    AudioConnection patchCord1(queue1, 0, i2s1, 0);
    AudioConnection patchCord2(queue1, 0, i2s1, 1);
    //AudioConnection patchCord(sine1,0,i2s1,0);
    AudioControlSGTL5000 sgtl5000_1;
    // GUItool: end automatically generated code
    
    uint8_t bufr[audiobuffersize * 2]; //buffer to hold 256 byte of audio data
    uint8_t bufcount; //received nrf24l01+ packet counter
    byte ControlBuffer[8];
    uint8_t ZielPipe;
    
    int i; //Counter
    int k; //temp
    
    void setup()
    {
    //Serial.begin(9600);
    bufcount = 0;
    
    AudioMemory(200); //give the Audio Library some memory to work with
    /*
    // use alternate SPI pins for nrf24
    SPI.setMOSI(7);
    SPI.setMISO(8);
    SPI.setSCK(14);
    SPI.begin();
    */
    // Setup the SGTL5000 AIC
    sgtl5000_1.enable(); //Enable the SGTL5000
    sgtl5000_1.volume(0.5); //set the headphone volume
    //sgtl5000_1.lineOutLevel(5, 5);
    /*
    sine1.frequency(500);
    sine1.amplitude(0.3);
    */
    radio.begin();
    //radio.setPayloadSize(32); //this is the maximum payload size for a packet transfer of nrf24
    radio.setAutoAck(false); //no Ack
    //radio.enableAckPayload();
    //radio.setRetries(1,2);
    radio.disableCRC(); //no CRC
    radio.setPALevel(RF24_PA_MAX);
    radio.setDataRate(RF24_2MBPS);
    radio.setChannel(121);
    delay(100);
    
    radio.openReadingPipe(1, pipeaddress[0]);
    radio.openReadingPipe(2, pipeaddress[1]);
    delay(50);
    
    radio.startListening();
    }
    
    void loop()
    {
    
    if (radio.available(&ZielPipe))
    {
      
      if(ZielPipe==1){
        
        radio.read(&ControlBuffer,8);
        
        for(i=0;i<8;i++){
          Serial.print(ControlBuffer[i]);
          
        }
        Serial.println("");
        
      }
    // get 8 packets a 32 byte audio data
    else if(ZielPipe==2){
    if ((bufcount >= 0) && (bufcount < 8))
    {
    // get 32 byte audio packet data
    radio.read(&bufr[bufcount * 32], 32);
    
    // test if all 8 packets received
    if (bufcount == 7)
    {
    bufcount = 0;
    int16_t *p = queue1.getBuffer();
    memcpy(p, &bufr[0], (audiobuffersize * 2));
    queue1.playBuffer();
    } else bufcount++;
    }
    }
    else{}
    }
    }
    Any ideas what to change/improve?

    Greetings, Chris

  2. #2
    Junior Member philwzen's Avatar
    Join Date
    Oct 2019
    Location
    Fiji
    Posts
    5
    have you tried the optimised teensy3 spi library spi4teensy3.h ? also if its just occuring with the joystick , is it the analogreads causing a problem, they are quite slow.
    try using this sort of thing.

    #include <ADC_Module.h>
    #include <RingBuffer.h>
    #include <RingBufferDMA.h>
    #include <spi4teensy3.h>

    ADC *adc = new ADC(); // adc object
    ADC::Sync_result syncvals;

    etc etc

    void setup()
    {

    spi4teensy3::init();

    // setup youre rf24 here ;

    // setup adc
    adc->setReference(ADC_REFERENCE::REF_3V3,0);
    adc->setReference(ADC_REFERENCE::REF_3V3,1);

    adc->setResolution(12,0); // 0 to 1023
    adc->setResolution(12,1); // 0 to 1023

    adc->setConversionSpeed(ADC_CONVERSION_SPEED::VERY_HIG H_SPEED,0);
    adc->setConversionSpeed(ADC_CONVERSION_SPEED::VERY_HIG H_SPEED,1);

    adc->setSamplingSpeed(ADC_SAMPLING_SPEED::VERY_HIGH_SP EED,0);
    adc->setSamplingSpeed(ADC_SAMPLING_SPEED::VERY_HIGH_SP EED,1);
    }
    void loop()
    {
    // useing syncvals you can red BOTH ADC's at the same time save a lot of time.
    syncvals = adc->analogSynchronizedRead(xpi,ypi); // xpi ypi the analog in pins you use
    SentRec is a struct with the fields xp int , yp int.

    SentRec.xp = syncvals.result_adc0;
    SentRec.yp = syncvals.result_adc1;// x+ y+

    // send data
    if (!radio.writeFast((char *)&SentRec,sizeof(SentRec),1)) {
    }
    }
    }

    might help.

  3. #3
    Junior Member
    Join Date
    Oct 2019
    Posts
    9
    Hey Phil,

    thanks for the idea! Gonna try to make it work with the tips you wrote!

    Greetings
    Chris

  4. #4
    Junior Member philwzen's Avatar
    Join Date
    Oct 2019
    Location
    Fiji
    Posts
    5
    anyjoy? what setting do use for spi on teensy with the rf24, mine dont want to play. radio. begin just hangs.

  5. #5
    Junior Member
    Join Date
    Oct 2019
    Posts
    9
    Hey Phil, finally had success transferring audio and data at the same time. I simply changed the SPI clock divider in the RF 24 Library (rf24.cpp) to a somewhat lower value.
    Furthermore i found out that one can't send too soon after an address change, otherwise the receiver might register a payload under the old address.

    Here you can see the MOSI of the TX on the bottom (yellow) and the MISO of the RX on the top (purple). It's so "noisy" because of the "if(radio.available())".
    Click image for larger version. 

Name:	DSC_0897_1.JPG 
Views:	6 
Size:	113.4 KB 
ID:	18130
    The spikes are an address change, 8 blocks of audio data, another address change and finally the joystick 'databufr'.
    Can't really be spaced much tighter without problems, but still a little room left - maybe for some kind of redundancy check/resend of lost packets. But i couldn't get this working yet. But still it works without errors if the two NRF24L01s are not too far apart (about 2m).

    The Code (TX):
    Code:
    //TX - Teensy 4.0 @ 600MHz
    
    #include <Audio.h>
    #include <SPI.h>
    #include <nRF24L01.h>
    #include <RF24.h>
    
    #define JoyX_PIN 16
    #define JoyY_PIN 17
    #define JoySW_PIN 18
    
    uint16_t JoyX;
    uint16_t JoyY;
    bool JoySW;
    
    #define audiobuffersize 128 // one block in audio library has 128 values of 2 byte
    
    RF24 radio(14,15); // CE, CSN
    
    uint8_t databufr[32];
    
    const byte pipeaddress[][6] = {"1Node","2Node"};
    
    // GUItool: begin automatically generated code
    AudioInputI2S i2s1;
    AudioOutputI2S i2s2;
    AudioRecordQueue queue1;
    AudioConnection patchCord1(i2s1, queue1);
    // GUItool: end automatically generated code
    
    uint8_t bufr[audiobuffersize * 2]; //buffer to hold 256 byte of audio data
    
    
    void setup()
    {
    Serial.begin(9600);
    sine1.frequency(300);
    sine1.amplitude(0.02);
    
    AudioMemory(100); //ca.100 oder mehr
    
    pinMode(JoyX_PIN, INPUT);
    pinMode(JoyY_PIN, INPUT);
    pinMode(JoySW_PIN, INPUT_PULLUP);
    
    delay(100);
    
    radio.begin();
    radio.setPayloadSize(32); //this is the maximum payload size for a packet transfer of nrf24
    radio.setAutoAck(false); // no Ack
    radio.disableCRC(); // no CRC
    radio.setPALevel(RF24_PA_MAX);
    radio.setDataRate(RF24_2MBPS);
    radio.setChannel(117);
    delay(50);
    
    radio.openWritingPipe(pipeaddress[0]);
    radio.stopListening();
    delay(100);
    
    queue1.begin();
    }
    
    void loop()
    {
    if (queue1.available())
    {
    radio.openWritingPipe(pipeaddress[0]);
    delayMicroseconds(150);
    
    memcpy(bufr, queue1.readBuffer(), audiobuffersize*2); // copy 256 byte audio data from audio library buffer to bufr
    queue1.freeBuffer();
    
    // send audio data in 8 packages a 32 byte to the FIFO buffers
    for (int i=0; i<8; i++)
    {
    radio.writeFast(&bufr[i * 32],32);
    delayMicroseconds(90);
    }
    JoyTX();  //after 8 Blocks of audio are sent
    }
    }
    
    void JoyTX(){      //collect Data from the Joystick and send it in a 32 Byte "databufr" to a different address than the audio.
      delayMicroseconds(150);
      radio.openWritingPipe(pipeaddress[1]);
      JoyX=analogRead(16);
      JoyY=analogRead(17);
      
      if(analogRead(JoySW_PIN)<=50){
        JoySW=true; 
        }
          else{
          JoySW=false;
          }
      databufr[0]=JoyX;
      databufr[4]=JoyY;
      databufr[7]=JoySW;
      
      delayMicroseconds(200);
      radio.write(&databufr,32);
      delayMicroseconds(150);
      
    }
    Code (RX):
    Code:
    //RX - Teensy 4.0 @ 600MHz
    // 
    
    #include <Audio.h>
    #include <SPI.h>
    #include <nRF24L01.h>
    #include <RF24.h>
    
    
    #define audiobuffersize 128 // one block in audio library has 128 values of 2 byte
    
    RF24 radio(16,17); // CE, CSN
    
    //const byte IRQ_Pin = 0;
    
    uint8_t pipeaddress[][6] = {"1Node","2Node"};
    uint8_t pipeNr;
    
    // GUItool: begin automatically generated code
    // defs for audio library
    AudioPlayQueue queue1;
    AudioOutputI2S i2s1;
    AudioConnection patchCord1(queue1,0, i2s1, 0);
    AudioConnection patchCord2(queue1, 0, i2s1, 1);
    AudioControlSGTL5000 sgtl5000; 
    // GUItool: end automatically generated code
    
    uint8_t bufr[audiobuffersize * 2]; //buffer to hold 256 byte of audio data
    uint8_t bufcount; //received nrf24l01+ packet counter
    uint8_t databufr[32];
    
    int k=0; //zeitmessung, debug
    elapsedMicros microsec;
    
    void setup()
    {
    //Serial.begin(9600);
    bufcount = 0;
    
    // Setup the SGTL5000 AIC
    sgtl5000.enable(); //Enable the SGTL5000
    sgtl5000.volume(0.5); //set the headphone volume
    //sgtl5000_1.lineOutLevel(5, 5);
    /*
    sine1.frequency(300);
    sine1.amplitude(0.2);
    */
    AudioMemory(150); //give the Audio Library some memory to work with
    
    
    
    radio.begin();
    radio.setPayloadSize(32); //this is the maximum payload size for a packet transfer of nrf24
    radio.setAutoAck(false); //no Ack
    radio.disableCRC(); //no CRC
    radio.setPALevel(RF24_PA_LOW);
    radio.setDataRate(RF24_2MBPS);
    radio.setChannel(117);
    delay(100);
    
    radio.openReadingPipe(1, pipeaddress[0]);
    radio.openReadingPipe(2, pipeaddress[1]);
    delay(50);
    
    radio.startListening();
    //pinMode(IRQ_Pin, INPUT_PULLUP);
    //attachInterrupt(IRQ_Pin,rfRead,FALLING);
    }
    
    void loop()
    {  
      if(radio.available(&pipeNr)){
        
        
        if(pipeNr==1){
          Serial.println("audiorecieved");
          if ((bufcount >= 0) && (bufcount < 8)){
          radio.read(&bufr[bufcount * 32], 32);
            // test if all 8 packets received
            if (bufcount == 7)
              {
              bufcount = 0;
    
              int16_t *p = queue1.getBuffer();
              memcpy(p, &bufr[0], (audiobuffersize * 2));    
              queue1.playBuffer();
              } 
            else {bufcount++;}
          }
         }
         else if(pipeNr==2){
          Serial.println("data");
         radio.read(&databufr,32);
         Serial.println(databufr[0]);
        }
       }
    }
    Chris

  6. #6
    Junior Member philwzen's Avatar
    Join Date
    Oct 2019
    Location
    Fiji
    Posts
    5
    ill have a look in abit when i get some time , maybe monday got a lot on at present. how many radio.writes do you get a second? it seems really slow for me i need to get up to the 50k writes a second ideally but it just manages about 7k !!! the analog read side is fine but when i put in the write it kills it.

  7. #7
    Junior Member
    Join Date
    Oct 2019
    Posts
    9
    What do you need those many transactions per second for? Maybe you can buffer some data and send it in packages? For my particular setup and code the minimum distance between two radio.write() was about 80usec. But maybe there is some faster way, I'm not sure..

  8. #8
    Junior Member philwzen's Avatar
    Join Date
    Oct 2019
    Location
    Fiji
    Posts
    5
    i am trying to replace an anaolog cable system with a wireless link, it send a minimum of 25k samples a sec but can be upto 50k. it is positional information so has to be accurate in the time domain. the receiver has to convert back to analog to send to the equipment under control. its a real old standard should have been digitised years ago but never was. unfortunately changiing the receiver to pure digitlal is not an option.

  9. #9
    Junior Member
    Join Date
    Oct 2019
    Posts
    9
    Maybe you could set the payload length to the minimum required for your data? don't know if it helps much, but maybe a little

  10. #10
    Junior Member philwzen's Avatar
    Join Date
    Oct 2019
    Location
    Fiji
    Posts
    5
    im sending a struct of 8bit inetgers alredy setting the maxsize
    radio.setPayloadSize(IldaSize * InDacRes);
    dependent on number of signals i need and input dac resolution.
    //Struct for data tansmission
    struct IldaData{
    unsigned int id : 8;
    unsigned int xp : 8;
    unsigned int yp : 8;
    unsigned int rp : 8;
    unsigned int gp : 8;
    unsigned int bp : 8;
    #if IldaSize > 5
    unsigned int xn : 8;
    unsigned int yn : 8;
    #if IldaSize > 7
    unsigned int rn : 8;
    unsigned int gn : 8;
    unsigned int bn : 8;
    #endif
    #endif
    }SentRec,OutRec;

  11. #11
    Junior Member
    Join Date
    Aug 2019
    Posts
    2

    Smile

    Quote Originally Posted by Chris314 View Post
    Hey Phil, finally had success transferring audio and data at the same time. I simply changed the SPI clock divider in the RF 24 Library (rf24.cpp) to a somewhat lower value.
    Furthermore i found out that one can't send too soon after an address change, otherwise the receiver might register a payload under the old address.

    Here you can see the MOSI of the TX on the bottom (yellow) and the MISO of the RX on the top (purple). It's so "noisy" because of the "if(radio.available())".
    Click image for larger version. 

Name:	DSC_0897_1.JPG 
Views:	6 
Size:	113.4 KB 
ID:	18130
    The spikes are an address change, 8 blocks of audio data, another address change and finally the joystick 'databufr'.
    Can't really be spaced much tighter without problems, but still a little room left - maybe for some kind of redundancy check/resend of lost packets. But i couldn't get this working yet. But still it works without errors if the two NRF24L01s are not too far apart (about 2m).

    Chris
    Hey Chris,

    I was just wondering what NRF24L01+ library are you using for this project?

    Thanks.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •