This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C1294NCPDT: LoRa device issue

Part Number: TM4C1294NCPDT

Hi everyone,

I turn to you because I have problems making two LoRa devices talk to each other.
I bought two SX1261DVK1BAS Development Kits and I separated one of these to integrate the SX1261 card into a card with a TM4C129.
The goal is to have the master with the TM4C129 and the slave with the second Dev Kit.
I have configured the parameters identically in order to permit them to communicate.

My problem is that when I try to send a signal with the first, the second receives nothing and when I send a signal with the second, the first does not receive anything either.

However I think I did the right thing at the init level, the configuration of the ports and the main ...

I'm a little desperate and really don't know what to do to find the problem.

Thank you very much for your help

Init :

void SX126xIoInit( void )
{
/* CS */
    MAP_GPIOPinTypeGPIOOutput(RADIO_NSS); //output
    GPIOPinWrite(RADIO_NSS,GPIO_PIN_4); //mise à 1 de la pin

/* BUSY */
    GPIOPinWrite(RADIO_BUSY, 0); //mise à 0 de la pin
    MAP_GPIOPinTypeGPIOInput(RADIO_BUSY); //input
    GPIOPadConfigSet(RADIO_BUSY, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU); //Pull Up enabled

/* IRQ */
    MAP_GPIOPinTypeGPIOInput(RADIO_DIO_1); // input
    GPIOPinWrite(RADIO_DIO_1, 0); //mise à 0 de la pin
    MAP_GPIOIntEnable(RADIO_DIO_1);
    GPIOPadConfigSet(RADIO_DIO_1, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU); //Pull Up enabled

/*ANT SW*/
    GPIOPinWrite(RADIO_ANT_SWITCH_POWER, 0); //mise à 0 de la pin
    MAP_GPIOPinTypeGPIOOutput(RADIO_ANT_SWITCH_POWER); //output

/* RESET */
    GPIOPinWrite(RADIO_RESET, 0); //mise à 0 de la pin
    MAP_GPIOPinTypeGPIOOutput(RADIO_RESET);

/* SPI SSI1 */
    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI1);

    GPIOPinConfigure(GPIO_PB5_SSI1CLK);
    GPIOPinConfigure(GPIO_PE4_SSI1XDAT0); // MOSI (TX)
    GPIOPinConfigure(GPIO_PE5_SSI1XDAT1); // MISO (RX)

    GPIOPinTypeSSI(SPI_CLOCK);
    GPIOPinTypeSSI(SPI_MOSI);
    GPIOPinTypeSSI(SPI_MISO);

    SSIConfigSetExpClk(SSI1_BASE,
                        HRD_u32SysClock,
                       SSI_FRF_MOTO_MODE_0,
                       SSI_MODE_MASTER,
                       SX126x_BIT_RATE,
                       SX126x_DATA_LENGHT);

    SSIEnable(SSI1_BASE);
}

void SX126xIoIrqInit(void)
{
    MAP_IntEnable(INT_GPIOC);
    MAP_GPIOIntTypeSet(RADIO_DIO_1, GPIO_RISING_EDGE);
    MAP_IntPrioritySet(INT_GPIOC, (6 << 5));
}

void SX126xReset( void )
{
      HRD_vdDelayMs(10);

      MAP_GPIOPinWrite(RADIO_RESET, 0);

      HRD_vdDelayMs(20);

      MAP_GPIOPinWrite(RADIO_RESET, GPIO_PIN_4);

      HRD_vdDelayMs(10);
}


void SX126xAntSwOn( void )
{
    GPIOPinWrite(RADIO_ANT_SWITCH_POWER, GPIO_PIN_2); //mise à 1 de la pin
}

void SX126xAntSwOff( void )
{
    GPIOPinWrite(RADIO_ANT_SWITCH_POWER, 0); //mise à 0 de la pin
}

Main :

const uint8_t PingMsg[] = "PING";
const uint8_t PongMsg[] = "PONG";

uint16_t BufferSize = BUFFER_SIZE;
uint8_t Buffer[BUFFER_SIZE];

States_t State = LOWPOWER;

int8_t RssiValue = 0;
int8_t SnrValue = 0;

/*!
 * Radio events function pointer
 */
static RadioEvents_t RadioEvents;

/*!
 * \brief Function to be executed on Radio Tx Done event
 */
void OnTxDone( void )
{
    Radio.Sleep( );
    State = TX;
}

/*!
 * \brief Function to be executed on Radio Rx Done event
 */
void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr )
{
    Radio.Sleep( );
    BufferSize = size;
    memcpy( Buffer, payload, BufferSize );
    RssiValue = rssi;
    SnrValue = snr;
    State = RX;
}

/*!
 * \brief Function executed on Radio Tx Timeout event
 */
void OnTxTimeout( void )
{
    Radio.Sleep( );
    State = TX_TIMEOUT;
}

/*!
 * \brief Function executed on Radio Rx Timeout event
 */
void OnRxTimeout( void )
{
    Radio.Sleep( );
    State = RX_TIMEOUT;
}

/*!
 * \brief Function executed on Radio Rx Error event
 */
void OnRxError( void )
{
    Radio.Sleep( );
    State = RX_ERROR;
}

void LoRa_Task(void * pvParrameters)
{
    bool isMaster = true;
    uint8_t i;

    // Target board initialization
    SX126xIoInit();
    //  SSI1_INIT_DYN();

    // Radio initialization
    RadioEvents.TxDone = OnTxDone;
    RadioEvents.RxDone = OnRxDone;
    RadioEvents.TxTimeout = OnTxTimeout;
    RadioEvents.RxTimeout = OnRxTimeout;
    RadioEvents.RxError = OnRxError;

    Radio.Init( &RadioEvents );

    Radio.SetChannel( RF_FREQUENCY );

    Radio.SetTxConfig( MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH,
                       LORA_SPREADING_FACTOR, LORA_CODINGRATE,
                       LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON,
                       true, 0, 0, LORA_IQ_INVERSION_ON, 3000 );

    Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR,
                       LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH,
                       LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON,
                       0, true, 0, 0, LORA_IQ_INVERSION_ON, true );

    Radio.Rx( RX_TIMEOUT_VALUE );

    while( 1 )
    {
       switch( State )
            {
            case RX:
                if( isMaster == true )
                {
                    if( BufferSize > 0 )
                    {
                        if( strncmp( ( const char* )Buffer, ( const char* )PongMsg, 4 ) == 0 )
                        {
                            // Send the next PING frame
                            strcpy( ( char* )Buffer, ( char* )PingMsg );
                            // We fill the buffer with numbers for the payload
                            for( i = 4; i < BufferSize; i++ )
                            {
                                Buffer[i] = i - 4;
                            }
                            HRD_vdDelayMs( 1000 );
                            Radio.Send( Buffer, BufferSize );
                        }
                        else if( strncmp( ( const char* )Buffer, ( const char* )PingMsg, 4 ) == 0 )
                        { // A master already exists then become a slave
                            isMaster = false;
                            // Send the next PONG frame
                            strcpy( ( char* )Buffer, ( char* )PongMsg );
                            // We fill the buffer with numbers for the payload
                            for( i = 4; i < BufferSize; i++ )
                            {
                                Buffer[i] = i - 4;
                            }
                            HRD_vdDelayMs( 1000 );
                            Radio.Send( Buffer, BufferSize );
                        }
                        else // valid reception but neither a PING or a PONG message
                        {    // Set device as master ans start again
                            isMaster = true;
                            Radio.Rx( RX_TIMEOUT_VALUE );
                        }
                    }
                }
                else
                {
                    if( BufferSize > 0 )
                    {
                        if( strncmp( ( const char* )Buffer, ( const char* )PingMsg, 4 ) == 0 )
                        {
                            // Send the reply to the PING string
                            strcpy( ( char* )Buffer, ( char* )PongMsg );
                            // We fill the buffer with numbers for the payload
                            for( i = 4; i < BufferSize; i++ )
                            {
                                Buffer[i] = i - 4;
                            }
                            HRD_vdDelayMs( 1000 );
                            Radio.Send( Buffer, BufferSize );
                        }
                        else // valid reception but not a PING as expected
                        {    // Set device as master and start again
                            isMaster = true;
                            Radio.Rx( RX_TIMEOUT_VALUE );
                        }
                    }
                }
                State = LOWPOWER;
                break;
            case TX:
                if( isMaster == true )
                {
                    //debug( "Ping...\r\n" );
                }
                else
                {
                    //debug( "Pong...\r\n" );
                }
                Radio.Rx( RX_TIMEOUT_VALUE );
                State = LOWPOWER;
                break;
            case RX_TIMEOUT:
                if( isMaster == true )
                {
                    // Send the next PING frame
                    strcpy( ( char* )Buffer, ( char* )PingMsg );
                    for( i = 4; i < BufferSize; i++ )
                    {
                        Buffer[i] = i - 4;
                    }
                    HRD_vdDelayMs( 1000 );
                    Radio.Send( Buffer, BufferSize );
                }
                else
                {
                    Radio.Rx( RX_TIMEOUT_VALUE );
                }
                State = LOWPOWER;
                break;
            case RX_ERROR:
                // We have received a Packet with a CRC error, send reply as if packet was correct
                if( isMaster == true )
                {
                    // Send the next PING frame
                    strcpy( ( char* )Buffer, ( char* )PingMsg );
                    for( i = 4; i < BufferSize; i++ )
                    {
                        Buffer[i] = i - 4;
                    }
                    HRD_vdDelayMs( 1000 );
                    Radio.Send( Buffer, BufferSize );
                }
                else
                {
                    // Send the next PONG frame
                    strcpy( ( char* )Buffer, ( char* )PongMsg );
                    for( i = 4; i < BufferSize; i++ )
                    {
                        Buffer[i] = i - 4;
                    }
                    HRD_vdDelayMs( 1000 );
                    Radio.Send( Buffer, BufferSize );
                }
                State = LOWPOWER;
                break;
            case TX_TIMEOUT:
                Radio.Rx( RX_TIMEOUT_VALUE );
                State = LOWPOWER;
                break;
            case LOWPOWER:
                break;
            default:
                State = LOWPOWER;
                break;
            }

            // Process Radio IRQ
            if( Radio.IrqProcess != NULL )
            {
                Radio.IrqProcess( );
            }

            HRD_vdDelayMs(10);
        }
}

  • Greetings,

    You've set yourself quite a task - have you not?    Usually (far) more basic projects should be successfully completed - before attempting, "Mt. Everest."

    You note that your "Initialization of the MCU" is correct.    It is not!    For one KEY example - review the "form" for "GPIOPinWrite()" - placed below:

    GPIOPinWrite(uint32_t ui32Port, uint8_t ui8Pins, uint8_t ui8Val)

    Clearly three parameters are required - yet your code (repeatedly - perhaps always) employs just two parameters!

    GPIOPinWrite(RADIO_NSS,GPIO_PIN_4);   

    You must follow the API's code format - there is (little) room for "originality."     This is but ONE error my staff has found - "YOU" must insure that your code "complies w/the form specified by the vendor's API."

    Here's a quick Diagnostic Procedure:

    • Review all code functions employed - insure they "Meet the API's format."
    • Are both "sides" of your equipment properly powered?    Have you measured during operation?
    • Job 2 (after bringing code into agreement w/the API) is to confirm that the MCU's SPI Output to your radio is to spec.   Are you sure that "Freescale Mode 0 is correct?"
    • Some ability to monitor RF would prove immensely helpful.   You should confirm that your SPI "load" of the radio has caused RF Output.   (sometimes a simple AM radio - placed w/in 2-3 cm of the radio - can detect the transmission)    Analog Devices produces low cost yet (reasonably powerful) RF detector ICs - some on eval boards.   (confirm that the radio is transmitting)
    • Replace the "too complex" code (i.e. strings) being Sent (hopefully received, too) with a "Burst of 30 or so characters" - your goal is to simply confirm transmission - then basic reception
    • Remove (most all) but the most basic code which enables Transmission & Reception.   Think "KISS" - Simplify, Measure - take one small (and measured/confirmed) Step at a time!

    You MUST proceed methodically (as the above guides) to efficiently succeed...

  • Hi,

    Valentin De Vargas said:
    when I try to send a signal with the first, the second receives nothing

    What signal from the master are you sending?

    Whether the signal you are talking about is a GPIO signal or the SSI, please use the scope to find out if the supposed signal is coming out of the device.

  • Hi Charles,

    Our posts crossed - poster has a severe error w/in his "GPIOPinWrite()" function calls - his code (as is) has "NO Chance" of working...

  • Hi cb1,

      Thank you for reviewing the poster's code and all the suggestions!

  • Hi cb1_mobile, thanks a lot for your time !

    • I'm sorry but i didn't give you the .h files, so for your point of view, it's normal that the API's format is not good, but in fact I have :
    #define RADIO_RESET                     GPIO_PORTC_BASE,GPIO_PIN_4
    #define RADIO_NSS                       GPIO_PORTB_BASE,GPIO_PIN_4
    #define RADIO_BUSY                      GPIO_PORTH_BASE,GPIO_PIN_0
    #define RADIO_DIO_1                     GPIO_PORTC_BASE,GPIO_PIN_5
    #define RADIO_ANT_SW_PWR                GPIO_PORTD_BASE,GPIO_PIN_2
    #define SPI_CLOCK                       GPIO_PORTB_BASE,GPIO_PIN_5
    #define SPI_MOSI                        GPIO_PORTE_BASE,GPIO_PIN_4
    #define SPI_MISO                        GPIO_PORTE_BASE,GPIO_PIN_5

    It's not an API's format issue because my code compiles well.

    I verified many times all theses ports and pins and everything is ok.

    • I have already tried to keep only  a ping buffer and the send function to be the most basic as possible but, it doesn't work neither.

    • When I put the dev kit in master mode and when i sand a message, the DIO2 is at 1 during the emission and at 0 before and after. But with the module with the TM4C, the DIO2 is never at 1, it stays at 0. So nothing is sent.

    • What do you mean when you say "Freescale Mode 0 is correct" ? 
    Can you explain to me a little better what you mean by that please ?


    There is something wrong in my code (maybe during the initialisation) but I can't find it ... :'(
  • Hi Charles Tsai, and thank you for your time as well !

    In fact i try to send a basic "PING" signal :

    #define RX_TIMEOUT_VALUE                            10000
    #define BUFFER_SIZE                                 8 // Define the payload size here
    
    
    #define RF_FREQUENCY                                868000000 // Hz
    
    #define TX_OUTPUT_POWER                             14        // dBm
    
    #define LORA_BANDWIDTH                              2         // [0: 125 kHz,
                                                                  //  1: 250 kHz,
                                                                  //  2: 500 kHz,
                                                                  //  3: Reserved]
    #define LORA_SPREADING_FACTOR                       9         // [SF7..SF12]
    #define LORA_CODINGRATE                             1         // [1: 4/5,
                                                                  //  2: 4/6,
                                                                  //  3: 4/7,
                                                                  //  4: 4/8]
    #define LORA_PREAMBLE_LENGTH                        8         // Same for Tx and Rx
    #define LORA_SYMBOL_TIMEOUT                         0         // Symbols
    #define LORA_FIX_LENGTH_PAYLOAD_ON                  false
    #define LORA_IQ_INVERSION_ON                        false
    
    #define SX126x_BIT_RATE         10000000    //10MHz
    #define SX126x_DATA_LENGHT      8           // 8 bits de données

    I think that my SPI signal is not good because I receive nothing but I have always something on my MISO (RX), even if I have nothing to receive ...

    I think it comes from the Dataput/Dataget but i can't find what's wrong.

  • Valentin De Vargas said:
    I think that my SPI signal is not good because I receive nothing but I have always something on my MISO (RX),

    You have two boards. I assume you are talking about from the perspective of the TM4C129 master board, correct? You are saying you see MISO on the master board (TM4C129 board) but not on the MOSI. Is this a correct understanding? If your TM4C129 master board is the SPI master then it is the one who is generating the SPI clock. How can the slave board drive the data if it doesn't see the SPICLK? Can you show a scope capture and perhaps draw what is the expected waveform and what you are seeing on the scope. 

    Valentin De Vargas said:
    I think it comes from the Dataput/Dataget but i can't find what's wrong.

    You have not shown any code on how you are calling the SSIDataPut and SSIDataGet.

  • Greetings,

    Your detailed explanation proved most helpful - what you report was "unexpected" yet (as you note) quite correct.

    Valentin De Vargas said:
    What do you mean when you say "Is Freescale Mode 0 correct"

    Your code notes:

    SSIConfigSetExpClk(SSI1_BASE,
    HRD_u32SysClock,
    SSI_FRF_MOTO_MODE_0,
    SSI_MODE_MASTER,
    SX126x_BIT_RATE,
    SX126x_DATA_LENGHT);

    It is (always) the SPI connected device which is the "Boss" - the MCU (usually being more capable) must adapt & satisfy the connected device.   Thus I asked that you confirm that your LoRa device indeed employs Freescale/Motorola Mode 0.    Is this now more clear?

    Kindly understand that my group does not "Know" your LoRa device - we (usually) cannot devote adequate time to 'new/exploratory learning' (i.e. your device's manual) till after the workday subsides.   Note: if you can "Justify your selection of (that) particular LoRa device" (over others) we can likely devote "More time to our investigation of its requirements."   (so that we may consider its purchase - for future use ... maybe)

    Valentin De Vargas said:
    When I put the dev kit in master mode and when i sand a message, the DIO2 is at 1 during the emission and at 0 before and after.

    This is an excellent piece of knowledge - very good & thank you!    Now we ask if, "Any device (i.e. an MCU or hardware) connects to the radio to enable the (eased, automatic, DEMO) "Sending of  Radio Messages."  (using just your dev kit's components - NOT the '129 MCU!)   If my staff was "with you" - we'd "tap into" those interconnect signals - log them - and then (later) "Send exactly those from your '129 MCU to the Radio."    Have you attempted that?

    You've not yet noted "Any Success" when using that Radio Pair in some kind of "Demo Mode."   Does such a Demo Mode exist?   If so - we strongly urge you to "Capture & Record each/every one of the signals passing to the radio - at each end......"

    This should enable further progress - or further questions - we (often) deploy radio & should be able to assist you in achieving communication success...

  • Hello again,

    We've made the effort to (further) investigate your kit - several "surprises" result.   (Along w/your motivation - as the kit provides an M4, ARM Cortex operating @ 168MHz (faster) - includes a DAC & is pre-programmed!)   Why would you retreat from that - especially when the bulk of the work has been successively completed?

    Your development kit includes:

    In addition - detailed PC Software is included and the (other/faster) ARM M4 MCU is "pre-coded & tested."   The cost of the development kit is ~300 (USD) - that's (many times) what was expected.

    These questions result:

    • Have you TWO such kits?    (so that you can communicate between the two?)    Has the price then doubled?
    • If you are able to "Inter-Communicate" you should be able to monitor (and record/log) the SPI Bus Traffic between the (included) TX-Side MCU & the Master (Transmitting) radio.
    • Your job then is to program your "replacement" MCU to duplicate the SPI waveforms captured during your (successful) "Demo Activation."

    By working systematically you should then be able to determine (which) SPI API functions produce the "Development Kit's SPI waveforms."   (such is the highly usual (& proven) means of "Reverse Engineering.")

    Yours is an advanced application - with (many) "Twists in the road" ... several of which prove "difficult to understand."    Even w/the promised "Extended Range" of "LoRa" - my team provides "extra time" to fully & properly test the radio connection under a variety of "weather, radio location, antenna & operational conditions" - and only then - "Commission the proposed Radio Link."     Good luck...

  • Hi Charles Tsai,

    In fact on the MOSI, i can see the registers adresses and the data of my instructions/configurations; that's normal.

    But on the MISO, i can see a signal while no signal is expected in reception.

    I don't know exactly where this signal comes from but now it works, it was a BUSY issue.

    Actually i didn't use corretly the pin BUSY, i wrote "while(MAP_SSIBusy(SSI1_BASE));" instead of "while(GPIOPinRead(RADIO_BUSY) == 0x01);" in my WaitOnBusy function.

    But you couldn't see it because, in order not to overwhelm my post with code, I didn't put everything.

    For example, the WaitOnBusy function is :

    void SX126xWaitOnBusy( void )
    {
        while(GPIOPinRead(RADIO_BUSY) == 0x01);
    //    while(MAP_SSIBusy(SSI1_BASE));
    }

    and the Datapu/Dataget function that i told before are :

    void
    SSIDataPut(uint32_t ui32Base, uint32_t ui32Data)
    {
        //
        // Check the arguments.
        //
        ASSERT(_SSIBaseValid(ui32Base));
        ASSERT((ui32Data & (0xfffffffe << (HWREG(ui32Base + SSI_O_CR0) &
                                           SSI_CR0_DSS_M))) == 0);
    
        //
        // Wait until there is space.
        //
        while(!(HWREG(ui32Base + SSI_O_SR) & SSI_SR_TNF))
        {
        }
    
        //
        // Write the data to the SSI.
        //
        HWREG(ui32Base + SSI_O_DR) = ui32Data;
    }
    
    void
    SSIDataGet(uint32_t ui32Base, uint32_t *pui32Data)
    {
        //
        // Check the arguments.
        //
        ASSERT(_SSIBaseValid(ui32Base));
    
        //
        // Wait until there is data to be read.
        //
        while(!(HWREG(ui32Base + SSI_O_SR) & SSI_SR_RNE))
        {
        }
    
        //
        // Read data from SSI.
        //
        *pui32Data = HWREG(ui32Base + SSI_O_DR);
    }
    
    uint8_t SX126xSpiInOut( uint32_t base, uint8_t dataIn )
    {
        uint32_t dataOut = 0;
    
        SSIDataPut(base, dataIn);
        SSIDataGet(base, &dataOut);
    
        while(MAP_SSIBusy(base));
    
        return (uint8_t) dataOut;
    }


    I realize that without all this info, you and cb1_mobile couldn't help me :'(

  • Hi cb1_mobile, and thanks a lot for your investigations.

    Concerning you question about "SSI_FRF_MOTO_MODE_0", yes I'm sure that it's correct because we're in rising edge, polarity 0 and phase 0.

    Like I said to Charles Tsai, today, it's working !!

    The problem was with the BUSY pin utilisation but i didn't give you this code, so you couldn't find it ...

    To answer to your question about the kits, yes i have two kits and about 300$ each ^^

    My goal is to reuse a certified board with a TM4C129 in order to make a LoRa project. The module which will be used is the sx1262 but the dev kit doesn't exist for europe yet, so i learn the Lora functionement and i play with the sx1261 version to be able to make it work with the TM4C129.

    I know that i can send a LoRa signal because the second LoRa dev kit see my sending but the signal format is surely not like expected by the dev kit because it appears "KO" and not "OK".

    And for the reception, it works quite fine because i receive the buffer message and the rssi, and everything seems to be realistic.

  • Hello again,

    Good for you - persistence was rewarded.

    Speaking of persistence - we suggest that you provide "adequate time & effort" to insure that your radio link succeeds:

    • at different times of day
    • under varying weather conditions & temperatures
    • and even when "Strong, local signals - from a variety of sources" arrive

    While "LoRa's appeal" is range extension and/or improved signal robustness over a lower power installation - do note that the "Antenna System" at each end - plays a "Highly Significant" role.   (possibly the greatest role!)    Should the link be fixed - highly directional antennas will strengthen the signal path while "limiting the level of unwanted/alien signals!"    (unless you are especially 'unlucky' - and those 'offending' signals are w/in your antenna's directed path...)