This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Multiple data sources transmission routing and identification

Dear Team, 

I'm preparing an application for nRF52840 that will require to send and receive data collected from two different sources, I2S and UART, two UART or SPI and UART channels. 
One of the connections will be lower in bps than the other but essentially they must arrive to the receiver and be routed to the correct UART, I2S or SPI port.
How do I route the packets to be sent to the correct interfaces at the destination (receiver)? 
On the other hand, I'll be interested in using the lowest latency protocol available (maybe ESB or Gazell). Other protocols could be used if the features are not availabe for those two. 

Is it possible to do this? 

About the bandwidth, I'll only need about 500/600 kbps as any audio traveling towards radio will be previously compressed and the other channel will be small control data to interface with the custom code and other peripherals. 

Thanks for your time and attention.
Best regards, 

Mental Mode

Parents
  • Hi Pablo

    How do I route the packets to be sent to the correct interfaces at the destination (receiver)? 

    You are free to do this any way you like. If you can combine all the serial data into a single packet then you can use the position in the packet to differentiate the different interfaces, and make sure to route the right parts of the packet to the right interfaces on the receiver end. 

    Alternatively you use one packet for each of the serial interfaces, and put some kind of command byte in the packet telling the receiver which interface the data is from. The drawback of this method is that it is not very efficient to send many small packets if you want to maximize data throughput. 

     

    Is it possible to do this? 

    For maximizing bandwidth I would recommend either ESB or BLE. ESB will give you lower latency and slightly higher maximum throughput, while BLE is easier to design in since the entire protocol is provided (the ESB protocol is quite simple, and will require more work on the software side). 

    Using BLE will also require BLE certification, which adds to the cost. 

    In both cases it is possible to do it, it's just a matter of priorities. 

    Best regards
    Torbjørn

  • Hi Torbjørn, 

    Do you have any example about both examples? Take into account that the custom command packets will be sent by the user only sometimes so, reserving space for that commands and interface in all packts will be pretty unnecesary. About creating whole packets with the commands per each interface may be a waste as you said so, If I have an example of each one I could create some kind of conditional packet building to mix them and not waste part of the packets that will be send continously from one of the interfaces.

    If you don't have examples of this, I could review any sample of packet building and origin-destination specification in the packet or interface.  
    Sorry if I'm asking these basic things but I'm pretty new on this technology Slight smile

    About protocols, I've been exploring that options and multiprotocol stacks.
    I have to say that the options are very flexible and seem to be pretty powerful...
    Maybe I'm little lost with frequency selection and tables... I read that there 80 channels for BRE to create necessary tables, but I have to study a way to make less populated selectable ones. What's the minimum frequency separation that I could use in ESB? Does it common to Gazell?

    Again, thanks for your time and patience. 

    Best regards, 

    Mental Mode

  • Hi Torbjørn,

    All clear. Now I have something to start from.
    Amazing support by the way guys. 

    Thanks a lot for your time and attention. 
    Have a great day! 
    Mental Mode. 

  • Hi Pablo

    Thanks for the kind words, and the best of luck with your project Slight smile

    Best regards
    Torbjørn

  • Hello

    Just for your to know, I've been programming for years in "too much high level" languages as Java, C# and so on... 

    I've been studying C++ in my free time the last 2 months, but at this point there are still things that I don't fully understand about the code proposed so... Let me put the code step by step and comment what I'm understanding. 

    Probably, you're so used to code for hardware using these compilers but I'm not so familiar with these types and operators. 

    I'll paste your program and comment my doubts about the original definition and transmitter part.

    The receiver part will be clarified with the transmitter part. 

    Again. I know that you're not here to teach C++. You're here to help to implement your solution.

    I'm using SES and run several examples so I'll able to test this at the moment you reply. 

    // COMMON STRUCT DEFINITION:
    
    typedef struct // Struct definition for dummy example. For me to understand how a struct is declared. 
    {
        uint8_t     cmd_byte; // Unsigned integer size 1 byte variable called cmd_by. I understood that this will be the “packet type” for my program to distinguish between i2c or whatever origin. To be able to put in the right port on receivers side.
        uint32_t    some_data; // Unsigned integer size 4 bytes variable called some_data. This is dummy thing to explain struct declaration.
        float       some_more_data; // Float type integer size float variable called some more data. Another dummy thing to explain another variable in case of wanting to send more than 1 data in the same struct type. 
    } packet_type_1_t;
    
    typedef struct 
    {
        uint8_t     cmd_byte; // here we are declaring what type of data I want to send to be routed by the receiver. 
        uint8_t     spi_data[4]; // Unsigned integer size 4 bytes ARRAY called some_data maximum 4 bytes in length. Is this the data size expected from SPI?
        uint8_t     i2c_data[6]; // Float type integer size float ARRAY called some more data maximum 6 bytes in length. Is this the data size expected for I2C data? 
    } packet_type_2_t;
    
    enum {PACKET_TYPE_1, PACKET_TYPE_2}; // Here you declare the two structs as unique types to be used in all the program. Take into account that my original program was intended to separate i2c and spi in two different structs but this is OK for me, 
    
    // TRANSMITTER PART:
    
    static uint32_t send_packet_type_1(packet_type_1_t *data_packet) // function declaration returning 4 bytes of static (doesn’t change each time is called) data called send_packet_type_1. **DOUBT** Are you passing the cmd_byte and the “deferenced pointer here? If that’s the case, why we don’t have the comma? 
    {
        nrf_esb_payload_t esb_payload = {0}; // Declaration of a variable using your struct type nrf_esb_payload_t called esb_payload and initialized to 0. 
    
        // Ensure that the cmd_byte field is set correctly, in correspondence with the packet type
        data_packet->cmd_byte = PACKET_TYPE_1; // Here, we are defining our data packet cmd byte struct as type 1. 
    
        // Populate the esb_payload struct
        memcpy(esb_payload.data, (uint8_t*)data_packet, sizeof(packet_type_1_t)); // Copy our unsigned 1 byte data packet variable to es_payload_data and defining the size of out whole struct. **DOUBT**Why the * in uint8_t?
        esb_payload.length = sizeof(packet_type_1_t); // Populating the required variable esb_payload.length with the size of the struct.
        esb_payload.pipe = 0; // Selecting the pipe to send it. **DOUBT** how many pipes do I can use?
    
        // Forward the data to the ESB library
        return nrf_esb_write_payload(&esb_payload); // Returning all the stuff to the nrf_esb_write_payload function.
    }

    Again, Thanks for your valuable help. 

    Best regards, 

    Pablo. 

  • Hi Pablo

    All our code examples including this one are based on C, not C++. 

    Technically C++ is a superset of C, but if you are reading about C++ you will get a lot of information about classes, inheritance, function overloading, exceptions etc which is not relevant to understand our C examples.

    In other words I would strongly suggest starting with a book on C to get familiar with the basics of the language, and then you can move to C++ later on if you need to learn all the additional features supported by C++. 

    A good start is what many consider the "bible" on the C language, "The C Programming Language by Kernighan and Ritchie", which even seems to be available for free here

    As for your questions, I tried to answer them inline:

    // COMMON STRUCT DEFINITION:
    
    typedef struct // Struct definition for dummy example. For me to understand how a struct is declared. TO: Correct
    {
        uint8_t     cmd_byte; // Unsigned integer size 1 byte variable called cmd_by. I understood that this will be the “packet type” for my program to distinguish between i2c or whatever origin. To be able to put in the right port on receivers side. TO: Correct
        uint32_t    some_data; // Unsigned integer size 4 bytes variable called some_data. This is dummy thing to explain struct declaration. TO: Correct
        float       some_more_data; // Float type integer size float variable called some more data. Another dummy thing to explain another variable in case of wanting to send more than 1 data in the same struct type. TO: Correct
    } packet_type_1_t;
    
    typedef struct 
    {
        uint8_t     cmd_byte; // here we are declaring what type of data I want to send to be routed by the receiver. TO: Correct. My proposal assumes that each struct will include this cmd_byte as the very first field, which means it will be the first byte in the packet .
        uint8_t     spi_data[4]; // Unsigned integer size 4 bytes ARRAY called some_data maximum 4 bytes in length. Is this the data size expected from SPI? TO: 4 and 6 were just random numbers I made up on the spot ;) How many bytes of SPI data and I2C data you get depends on the sensor you are talking to, and should be specified in the sensor datasheet.
        uint8_t     i2c_data[6]; // Float type integer size float ARRAY called some more data maximum 6 bytes in length. Is this the data size expected for I2C data? TO: Same as above
    } packet_type_2_t;
    
    enum {PACKET_TYPE_1, PACKET_TYPE_2}; // Here you declare the two structs as unique types to be used in all the program. Take into account that my original program was intended to separate i2c and spi in two different structs but this is OK for me, 
    // TO: An enum is simply a way to define constant values that are guaranteed to get unique values, that you can then put into the cmd_byte field for the different structs. By default the first constant will have value 0, the next value 1 and so on. The following code would be equivalent:
    //#define PACKET_TYPE_1 0
    //#define PACKET_TYPE_2 1
    
    // TRANSMITTER PART:
    
    static uint32_t send_packet_type_1(packet_type_1_t *data_packet) // function declaration returning 4 bytes of static (doesn’t change each time is called) data called send_packet_type_1. **DOUBT** Are you passing the cmd_byte and the “deferenced pointer here? If that’s the case, why we don’t have the comma? 
    // TO: In C a static function declaration is only available within the same file, telling the compiler that this function should not be available to other files.  Think of it as a "private" function in C++ or C#. Static variables are different, but there are plenty of guides online describing the static keyword in C
    // TO: packet_type_1 is the type, data_packet is the name, and the * means you are passing a pointer to the struct, not the struct itself
    {
        nrf_esb_payload_t esb_payload = {0}; // Declaration of a variable using your struct type nrf_esb_payload_t called esb_payload and initialized to 0. // TO: Correct. The {0} initialization is a simple way to set all the struct fields to 0.
    
        // Ensure that the cmd_byte field is set correctly, in correspondence with the packet type // TO: Correct
        data_packet->cmd_byte = PACKET_TYPE_1; // Here, we are defining our data packet cmd byte struct as type 1. //TO: Correct
    
        // Populate the esb_payload struct
        memcpy(esb_payload.data, (uint8_t*)data_packet, sizeof(packet_type_1_t)); // Copy our unsigned 1 byte data packet variable to es_payload_data and defining the size of out whole struct. **DOUBT**Why the * in uint8_t?
    	// TO: The memcpy function expects a pointer to an array of bytes (aka uint8_t), and the compiler will complain if we provide it a pointer to a packet_type_1_t struct. By casting the data_packet pointer to an uint8_t pointer we are essentially telling the compiler to treat this as a uint8_t pointer, and you should not get a warning. Most compilers will allow you to use the pointer without a cast, but it is good practice to remove all warnings from your code. 
        esb_payload.length = sizeof(packet_type_1_t); // Populating the required variable esb_payload.length with the size of the struct. // TO: Correct
        esb_payload.pipe = 0; // Selecting the pipe to send it. **DOUBT** how many pipes do I can use? // TO: The maximum number of pipes is set by the NRF_ESB_PIPE_COUNT define in nrf_esb.h, and because of hardware limitations this number can not be larger than 8. With 8 pipes the valid pipe range is 0-7
    
        // Forward the data to the ESB library
        return nrf_esb_write_payload(&esb_payload); // Returning all the stuff to the nrf_esb_write_payload function. // TO: Possibly this call is a bit confusing if you're new to C. Essentially you first call nrf_esb_write_payload and provide a pointer to the esb_payload struct that you just populated, and then you are returning the return value from the nrf_esb_write_payload function to whoever calls the send_packet_type_1 function. This return value can be used to detect errors return from the nrf_esb library, like if you try to use an invalid pipe, invalid packet length etc. 
    	// An equivalent and more intuitive way to write this line is:
    	// uint32_t error_code = nrf_esb_write_payload(&esb_payload);
    	// return error_code;
    }

    Best regards
    Torbjørn

  • Hi Torbjørn,

    Amazingly explained... Thanks a lot! 

    And for the literature proposal! I'll check out that to be more concentrated on plain C.
    I'll be doing experiments with modified versions of the examples and my own code but now I have the basic bricks. 

    I promise not bothering you with code related stuff. :) 

    Thanks again and have a great week. 
    Best regards, 

    Pablo. 

Reply Children
Related