The more we know the harder it is to defeat us!

Long range wireless communication is getting more and more attention. Today, I would like to share with you my experience with a LoRa module — SX1278 and also the drive for this device.

LoRa took its name from “Long Range”. It is a proprietary communication system which is using chirp spread spectrum radio modulation technology. In other words, it uses chirps to encode a piece of information. What is really interesting about the LoRa is a fact that it can transmit data over very long distance. By very long distance I mean over a couple of kilometres and sometimes more and all of this is done very power–efficiently.

I decided to work on SX1278 LoRa module. It is an affordable radio module and offers not only LoRa but other types of modulation like FSK. The test platform is an STM32F103C8T6 development board.

Prerequisite

You need two boards equipped with STM32F103C8T6 MCU and two SX1278 modules.

One of the boards will work as master and the other one will work as slave. Master is sending data to slave. Both boards have the same firmware. The mode in which the board is working in is determined by the state of input pin PB2.

Above you can see screen shoot from CubeMX where MCU’s pins are configured.

To actually see what is being send over via radio SWV interface was used. For this to work you need to have a debugger, preferably ST-Link V2, with support for SWV. Sometimes when you want to take advantage of SWV it does not work out of the box. The most probable reason for this is that the debugger firmware outdated. Please remember to upgrade the firmware of ST-Link in advance.

Wiring

The module has to be connected with the MCU board with following pins:

MCU pin SX1278 pin Description
PA4 NSS SPI chip–select
PA5 SCK SPI SCK
PA6 SO SPI MISO
PA7 SI SPI MOSI
PB0 DIO0 LoRa interrupt indicator pin (for receiver mode)
PB1 RST LoRa reset
——- ———- ———–
VDD VCC +3V3
VSS GND GND

The SX1278 communicates with STM32 MCU via SPI those are PA4, PA5, PA6 and PA7. There are two other logic pins — PB0 which is DIO0 of radio module and PB1 which is Reset pin of this module. The meaning of the reset input if obvious, what is not is the DIO0. It is used for pulling the state of LoRa module. If the DIO0 output is high it means that there are received data and MCU can read it. MCU can be configured for detecting rising edge to trigger immediate action of reading the data. However, in this example polling was used (checking manually if the DIO0 is high).

Compilation

The example was prepared for SW4STM32 IDE. However, nothing stands in the way to use other IDE like i.e. TrueSTUDIO – Atollic.

Run

After flashing the image you should mind the PB2 port. It is configured as input and depending on its state the board boots as a master or as a slave. For master mode the PB2 has to be pulled high. For slave mode the PB2 has to be pulled low.

All the communication is going through redirected printf() function to SWV. To read the communicates you have to have ST-Link Utility installed. There you can chose Printf via SWO viewer and set the right frequency.

Before you start transmitting and receiving data via LoRa you need to set up the driver. Below is an example how to do this.

Provided example works in ordinary fashion, the master board is constantly sending messages while the slave is constantly reading them. That’s simple, isn’t it? Below a code snippet was provided to clarify the situation.

 

Working example

Below you can see two screen shoots. The first one shows a log from master session. The second image shows a log from slave session.

Master:

Slave:

Source code

If you are intrigued enough you can go and download the driver or the whole example. Both are available at my github. The driver is written in C and it can be easily ported to other targets. Also the hardware layer was separated from the driver logic so it is not a hassle to actually port it.

The driver — SX1278

The example — SX1278-example

53 Responses to STM32 HAL driver for LoRa SX1278 wireless module

  • saeed says:

    hi, thanks for your blog.
    i have two stm32l152 and lora sx1278. i’m going to send and receive data with keil IDE.
    your example is for SW4STM32.
    could you help me please?

    • Yes, the example was prepared for SW4STM32. Unfortunately, I do not use Keil software but you should be able to import this example. If not you can try to create an empty project and copy source files which are inside SX1278-example repository — it should work flawlessly.

    • As a matter a fact I have forgotten to mention a different path.
      You can take the STM32CubeMX file and change the Toolchain to MDK-ARM and regenerate the code. I think it will be the most straight forward way to do this.

  • pooriya says:

    Hi thank you.
    i have questions!
    What is the maximum distance?
    and how can we get it?
    The program must be change?

    • I am still planning to do some range testing. You do not have to change the program. However, tweeting the parameters as spread factor can give you better results.

  • pooriya says:

    I ask some where if you shift 0x10000 in DIO1 – 5 . in for example 1 ms .it work for 9600 meters.
    but i don’t test it.

    • Sorry, but I do not know how it should work. The DIO pins are described in the datasheet and they perform specific functions as described in there. Where did you get that idea?

  • John says:

    hi
    Thanks for sharing your works.
    but i have a little problem with your project. Can you help me with project for stm32f0?
    i use two board for test, and i make program for master and slave and it not work…maybe you can check my project?
    thank you

  • John says:

    yes. copy your project on the stm32f0 via cube after generate code and add your files gpio/spi/sxlib and i use your code from main file. I change pin for my board and now my project success compile. But between board tx/rx not work
    if you want i can send my project with cube on your mail

    • You are only required to copy the driver of the SX1278 and some of the code from main. While regenerating the code Cube will take care of adjusting GPIO and so on. You should not copy them to the new project. Just a quick question, did you connected all required pins of the LoRa module to your STM32?
      You can send it to me but I do not have STM32F0 to check it. The best way of sharing your project would be by using Github and sending me a link to it.

    • Ok. I took a look at your code. Everything looks all right. The reason you do not see anything is that because you did not redefined _write() function. In the example I am using SWV as a debug interface. It is using SWO pin at which it is sending the data. You could use an UART interface if you wish.

  • John says:

    thank you,. yes, now i use interface usart for debug. Now i make
    if (master == 1) {
    HAL_USART_Puts(USART1,”Mode: Master\r\n”);
    HAL_GPIO_WritePin(…);

    //init lora module

    HAL_USART_Puts(USART1, “Configuring LoRa module\n\r”);

    now in my serial port i see only the master, but I do not see the initialization parameter and other parameters 🙁

    • Where did you get this function HAL_USART_Puts() from? From HAL lib you get only HAL_UART_Transmit() and similar. I advice you to sort out the communication first. After that you can use it to properly redefine _write() to use your serial interface as output for printf(). Also, the less you change the original code the better. The example I have uploaded works and was tested with STM32F1 and it should work also for you. I have confirmations that it was also ported to STM32F4 where it also works. You only need to sort out the communication issue.

    • You welcome! As for the SWV that is why I did write to use a serial interface like UART. Then you only need to redefine the _write() function and everything should work out of the box provided that the serial interface is properly configured. Redefinition of _write() function can look like this for UART:

      int _write(int file, char *ptr, int len) {
      HAL_UART_Transmit(&huart2,ptr,len,50);
      return len;
      }

    • Yes, I have some nucleo for F4 but if you are going to ask if I have used it on that board then no. However, as I have written earlier I know that one guy has successfully run the code on STM32F4.

  • John says:

    i can’t launch your library. Did the necessary for checks SPI and he work, the registers are read and written, the state of GPIO is the same as yours, what else needs to be change? If there is an opportunity, share an example for a f4disc…

  • John says:

    in serial wire i see only:

    Mode: Slave
    Configuring LoRa module
    Done configuring LoRaModule
    Slave …
    Receiving package…
    Received: 0
    Package received …
    Slave …
    Receiving package…
    Received: 0
    Package received …
    Slave …

    and master side:

    Master …
    Sending package…
    Entry: 0
    Sending Hello 2
    Transmission: 0
    Package sent…
    Master …
    Sending package…
    Entry: 0
    Sending Hello 3

    what i can check for launch lib?

    • It seams that the Master does not send any data. Look at what you have received from debug log of the Master:

      Transmission: 0

      It means that the function SX1278_LoRaTxPacket() returned 0 because of timeout. There was no signal on DIO0 of the SX1278. Also check what value is returned by
      ret = SX1278_LoRaEntryTx(&SX1278, 16, 2000);
      at the very beginning.

  • John says:

    oh, yah, i see, on the tx board not needed use DIO for transmit. Now in the debug i see:

    Transmission: 1
    Package sent…
    Master …
    Sending package…
    Entry: 1
    Sending
    Transmission: 1
    Package sent…
    Master …
    Sending package…
    Entry: 1
    Sending
    Transmission: 1
    Package sent…
    Master ..

    but not see it on the receiver

    • What did:
      ret = SX1278_LoRaEntryRx(&SX1278, 16, 2000);
      return?
      Also, below function:
      ret = SX1278_LoRaRxPacket(&SX1278);
      is also using DIO0 to know if there are any pending data to be read. From what you have written before I think that you did not connect the DIO0 on the slave side.
      Please connect all pins as described in the table inside the post.

    • Reading raw value from LoRa module is pretty straightforward. However, SX1278_RSSI_LoRa() returns RSSI after some calculations. The way you calculate the RSSI differs depending on what configuration you are using. Please refer to SX1278 documentation for more information.

  • Huzaifah says:

    Thank you so much for your help, actually i want o implement code of SX1278 on STM32L152 as you mentioned earlier i have added the header files and other necessary files into the folders but i have one doubt regarding the pins,
    1. MODE pin where i have to connect on board and on Module.
    2. Same for the DIO0 pin.
    Thank You!

    • The MODE pin can be any GPIO configured as input same goes for DIO0. Just remember to update hardware initialization structure for LoRa module:
      SX1278_hw.dio0.port = DIO0_GPIO_Port;
      SX1278_hw.dio0.pin = DIO0_Pin;
      The MODE pin is selecting whether the board works as master or as slave. If you stick to the same labels in Cube and regenerate code everything should work right of the box. Since you are running this example on STM32L1 the easiest way is to import my example and change appropriate pins.

  • StraryAnoda says:

    Hi
    Why does the transmission crash when the send time is accelerated from 2,500 milliseconds to for example 100 milliseconds?

    • I did no try this out. But you can do that kind of experiment. The minimum gap between data transfers is defined by the parameters of transmission and how many data you want to send. You can calculate it based on datasheet of SX1278 device.

  • Lê Thanh Dương says:

    Hi,
    I did followed your instructions with the Dragino LoRa Shield instead of SX1278. I connected the wire and also use SX11278.c to do just like you. However, ret = SX1278_LoRaEntryTx(&SX1278, message_length, 2000) or ret = SX1278_LoRaTxPacket(&SX1278, (uint8_t *) buffer, message_length, 2000) always returned to 0 not 1 like you to send and receice the package. I do not know how to fix that. I used KeilC to do that. Do you have any idea to solve it?

    • My first step in solving this would be to actually check if there is proper ongoing SPI transmission. You can verify that by reading some register with constant value or using a logic analyser. SX1278_LoRaEntryTx() returns 0 when the timeout has been reached. That is why I would check SPI communication first.

  • Luqman says:

    Hi,
    can i use multiple transmitters sending data to one receiver with your driver? i have a project to set multiple node of wireless sensor network, and i’m interested to use sx1278 lora module and stm32f103.

    • Yes, you can do this. There are two ways. You can use single SPI and share MISO, MOSI and SCK pins (as it was intended) or you can use different SPIs. The best way would be to use single SPI and multiple CSes (chip select pins) to chose with which device you want to communicate with. Also remember to use different pins for DIO0 and RST for each LoRa module.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Donate

If you like my blog please consider a small donation.

Subscribe to Blog via Email

Enter your email address to subscribe to this blog and receive notifications of new posts by email.

Join 234 other subscribers