RAK3172

From Stm32World Wiki
Revision as of 11:18, 17 September 2023 by Niclas (talk | contribs) (Fixed the accidental swap of PB8 and PC13)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

RAK3172 from RAK Wireless comes in varies different packages, but under the hood we have an STM32WLE5 with 64kB RAM and 256kB Flash, and LoRa communication capabilities. STM32CubeMX has LoraWAN support, but requires a little bit of "expertise" to get it to work properly.

Here is a guide from Andrew Larkin (with permission), on how to get a skeletal application working from scratch (assuming familarity with STM32CubeMX).

RAK3172 LoraWAN Setup with STM32CubeMX

Author: Andrew Larkin/Arcadius Systems

Revision: 1.2

Overview

The RAK3172 LoRaWAN radio module is supplied with RAK’s RUI3 firmware that can be used as is. However, for some applications, it is desirable to implement native firmware from the ST source using STM32CubeIDE.

Introduction

The RAK3172 module from RAKWireless is based on the STM32WLE5CC MCU with SubGHz radio chip Setting up a new STM32CubeIDE project from scratch starts with configuring the .ioc file, which will then generate the basic project files. Getting the configuration correct is essential to not only the operation of the RAK3172 but also to getting the chip into the minimum power state for maximum battery life. There are low frequency and high frequency variants of the RAK3172. The low frequency variant targets radio frequencies in the 433MHz band, while the high frequency variant covers the 860- 930MHz band. Each variant is available with the option of an onboard IPEX antenna connector.

There are now two versions of the RAK3172:

  • RAK3172 which uses a 32MHz crystal as reference for the radio.
  • RAK3172-T which uses a 32MHz temperate compensated crystal oscillator (TCXO) as the reference.

The difference between these two relates to the operating temperature of the module.

The RAK3172 has a minimum operating temperature of -20°C, while the RAK3172-T claims[1] a minimum operating temperature of -70°C.

Both variants claim a maximum operating temperature of +85°C.

In this guide, we will only be considering the requirements for the RAK3172 module itself and not the rest of the application circuit.

For minimum power consumption, the application circuit design should consider the effect on current draw when the MCU pins are in reset (high impedance) state – that is, the pins are not being actively driven by the MCU. This may necessitate the use of external pullup resistors in the circuit to hold signals in the required low-power states – the general design rule is don’t allow pins to float. At the time of writing, the version of STM32CubeIDE being used was 1.13.1

Setting up new project

After starting STM32CubeIDE,

  1. . Select an existing workspace or create a new workspace.
  2. . Select “File/New/STM32 Project” to start the new project wizard.
  3. . Select STM32WLE5CCU7 as the target MCU, then hit “Next”.
  4. . Enter a project name and select a project location, then hit “Next”.
  5. . Hit “Finish” and wait for the initial project to be set up.

This will build all the basic files for the project and then bring up the .ioc file configuration tool.

Setting up the IOC file

The Configuration tool is used to set up the chip and the software libraries. When it builds the code, it will also provide template files for the user application – which will then need to be completed for the final code.

Setting up RAK3172 pins

There are several pins of the MCU that are used internally by the RAK3172. Left-click on a pin to assign a mode to the pin. Right click on a pin to bring up a menu that will allow you to change the “user label” of the pin.

Radio Control Pins
Pin Mode Name Function
GPIO_Output RF_SW_CTRL1 Controls Tx/Rx switch
GPIO_Output RF_SW_CTRL2 Controls Tx/Rx switch
GPIO_Input FREQ_HIGH[2] Pin is tied to either Vdd or Gnd to indicate band variant

Additional pins relating to the application circuit can also be configured at this point. There are some additional pin configuration options under the System Core/GPIO section.


For RB8 (“RF_SW_CTRL1”), set the “Maximum output speed” option to “Very High”[3]

Setting up RCC

Under System Core/RCC:

  • Set High Speed Clock (HSE) to
    • “Crystal/Ceramic Resonator” for RAK3172
    • “TCXO” for RAK3172-T
  • Set Low Speed Clock (LSE) to “Crystal/Ceramic Resonator”

Setting up SYS

Under System Core/SYS:

  • Set Timebase Source to “None”

Setting up ADC

Under Analog/ADC

  • Enable “Temperature Sensor Channel” – used to monitor MCU temperature as example in sys_sensors.c
  • Enable “Vrefint Channel” – used to monitor battery voltage

In “Parameter Settings”

  • Clock Prescaler: “Synchronous clock mode divided by 4”
  • Auto Off[4]: “Enabled”
  • Trigger Frequency[5]: “Low frequency”
  • Overrun behaviour: “Overrun data overwritten”
  • SamplingTime Common 1: “160.5 Cycles” [Unsure if required]
  • SamplingTime Common 2: “160.5 Cycles” [Unsure if required]

Setting up RTC

Under Timers/RTC

  • Activate Clock Source: Checked
  • Activate Calendar: Checked
  • Alarm A: Internal Alarm A

In the Parameter Settings: Start by setting Bin Mode to “Free running Binary mode”. Other available settings will change. Then

  • Asynchronous Predivider value: “RTC_PREDIV_A” (has to be typed in)
  • Alarm A/Binary AutoControl: RTC_ALARMSUBSECONDBIN_AUTOCLR_NO

Under the NVIC Settings:

  • RTC Tamper, RTC TimeStamp, LSECSS and RTC SSRU Interrupts: Enabled[6]
  • RTC Alarms (A and B) Interrupt: Enabled
Radio Control Pins
Constant Name Constant Value
RTC_PREDIV_A ((1<<(15-RTC_N_PREDIV_S))-1)
RTC_N_PREDIV_S 10
RTC_PREDIV_S ((1<<RTC_N_PREDIV_S)-1)

Setting up SUBGHZ

Under Connectivity/SUBGHZ

  • Activated: Checked

Under Parameter Settings

  • Baudrate Prescaler Value: 4[7]

Under NVIC Settings

  • SUBGHZ Radio Interrupt: Enabled

Setting up USART

There are two options for setting up the USART:

  • LPUART1
  • USART2

Both use the same GPIO pins. The difference between the two is the behaviour when the MCU is in low power mode.

When the MCU is in STOP2 mode, USART2 is turned off. However, LPUART1 will still operate in STOP2. What this means is that if the application wants to be able have the MCU wake up when it receives serial data, LPUART1 will be required.

The limitation is that LPUART1 will need to be clocked from the 32768Hz LSE crystal which limits it to 9600 baud.

For the purposes of this document, we will be configuring the UART to use USART2.

Selecting Connectivity/USART2:

  • Set Mode: Asynchronous

Under Parameter Settings:

  • Fifo Mode: Enabled

Under DMA Settings:

  • Add DMA Request USART2_TX on DMA1 Channel 1

Under NVIC Settings

  • USART2 Interrupt: Enable

Setting up LoRaWAN

Under Middleware and Software, LORAWAN

  • Enabled: Checked

There is a lot to configure here and the needs of the application will determine the options required. This description will concentrate on just one configuration – your application will likely need to vary this.

There are three application types supported:

  • AT Slave skeleton
  • End Node Skeleton
  • User defined skeleton

The selection of application skeleton will determine which files are generated by the IOC Configuration. The list of options will be very different for each application type.

Note that some of the generated files won’t be regenerated if the application type changes as they are templates for application code – so if your options look different to these, it may be because the application type has been set differently.

Under LoRaWAN application

  • Application: End Node Skeleton

Configuration of End Node application

Under LoRaWAN middleware

  • Check the region support option for your application. You can uncheck regions that you

don’t want/need to support. Our application is for Region Australia freq 915, so it gets checked.

  • [Optional] Enable the context management storage: check
  • [Optional] Select the LoRaWAN Link Layer specification version: v1.0.4
  • [Optional] Enable the additional LoRaWAN packages: check
  • [Optional] Select the LoRaWAN packages version: v1.0.0
  • Radio maximum wakeup time (in ms): 10
    • Note that this value will depend on whether TCXO is being used
  • Select radio Driver: User Board[8]
  • Tx Rfo Config: CONF_RFO_HP or CONF_RFO_LP, depending on which RAK3172 variant is

used. Do not leave on the default.

The MCU has two different pins for radio Tx and this final option controls which pin is used. Only one of the pins is connected to the internal RF switch, so if you get the selection wrong, the radio transmitter won’t be connected to the antenna! Not only will this not work, it may potentially damage the transmitter.

Back under LoRaWAN Application:

  • Send Tx on Timer or Button Evt: TX_ON_TIMER
  • Active Region: <Set as required> LORAMAC_REGION_AU915
  • Transmit duty cycle: <Set as required> 20000

Under LoRaWAN Commissioning

  • LoRaWAN device EUI: provide a unique 8-byte value [DevEUI]
  • App/Join EUI: provide a unique 8-byte value [JoinEUI]
  • Network key: provide a unique 16-byte value [NetKey]

The DevEUI, JoinEUI, and NetKey are the three critical codes required to add the end node to a LoRaWAN network. Refer to the LoRaWAN standards for how to generate these values.

Under Platform Settings

  • ADC Found Solutions: ADC
  • USART IPs or Components: USART: Asynchronous
  • USART Found Solutions: USART2
  • RTC Found Solutions: RTC

Setting up NVIC

Now that most of the hardware is set up, there are some settings to adjust under System Core/NVIC

  • DMA1 Channel 1 Interrupt Preemption Priority: 2
  • USART2 Interrupt Preemption Priority: 2

Change the Preemption Priority by:

  1. . Select the relevant row in the NVIC table
  2. . Select the Preemption Priority in the drop down box at the bottom

Clock Configuration

Under the Clock Configuration tab

  • RTC Clock Mux: LSE
  • MSI RC: 48000
  • System Clock Mux: MSI
  • HSE Input Frequency: 32

Setting up the Project Manager

Under Code Generator

  • Generate peripheral initialization as a pair of ‘.c/.h’ files per peripheral: checked
  • [Optional] Backup previously generated files when regenerating
  • Set all free pins as analog (to optimize power consumption): checked

Under Advanced Settings

Generating the Project Code

When you save the IOC file, it will generate the project code.

The code generated will contain code modules (‘.c’ files) that may be regenerated if you later change IOC file options, as well as template modules that won’t be regenerated that contain things like board specific code.

As this is not intended as a comprehensive guide to developing a LoRaWAN application, detailed description of all the files will be left to ST documentation and comments in the modules themselves.

To get an operational LoRaWAN program running on the RAK3172 specifically, some specific coding will be needed.

Implementing Radio Interface

Under the LoRaWAN/Target folder are three files related to the RAK3172:

  • radio_board_if.h
  • radio_board_if.c
  • radio_conf.h

radio_conf.h

In radio_conf.h, there are a couple of values that are cannot be set via the IOC file and, unfortunately, are also not protected from being overwritten by code regeneration.

The two values we care about are:

  • XTAL_DEFAULT_CAP_VALUE
  • TCXO_CTRL_VOLTAGE (in the case of RAK3172-T)

To deal with this, we have to put our changes under /* USER CODE BEGIN EC */ as follows:

/* USER CODE BEGIN EC */
/* Values above for XTAL_DEFAULT_CAP_VALUE and TCXO_CTRL_VOLTAGE are
* not protected from being overwritten by code regeneration, so we
* replace them here where it is safe
*/
#undef XTAL_DEFAULT_CAP_VALUE
#define XTAL_DEFAULT_CAP_VALUE ( 0x10UL )
#undef TCXO_CTRL_VOLTAGE TCXO_CTRL_1_7V
#define TCXO_CTRL_VOLTAGE TCXO_CTRL_3_0V
/* USER CODE END EC */

The value of XTAL_DEFAULT_CAP_VALUE of 0x10UL comes from the RAKWireless RAK3172 Low Level development reference files. For TCXO, this may need to be (0x0UL):

radio_board_if.h

In this file, under the comment “/* USER CODE BEGIN Exported PinMapping */”

Delete the “#warning” line under the comment

This warning is a reminder to provide board definition pins – which has already been done in the IOC file.

radio_board_if.c

Under the comment “/* USER CODE BEGIN RBI_ConfigRFSwitch_2 */”

Replace the “#warning” line with the following code:

switch (Config)
{
    case RBI_SWITCH_OFF:
    {
        /* Turn off switch */
        HAL_GPIO_WritePin(RF_SW_CTRL1_GPIO_Port, RF_SW_CTRL1_Pin, GPIO_PIN_RESET);
        HAL_GPIO_WritePin(RF_SW_CTRL2_GPIO_Port, RF_SW_CTRL2_Pin, GPIO_PIN_RESET);
        break;
    }
    case RBI_SWITCH_RX:
    {
        /*Turns On in Rx Mode the RF Switch */
        HAL_GPIO_WritePin(RF_SW_CTRL1_GPIO_Port, RF_SW_CTRL1_Pin, GPIO_PIN_SET);
        HAL_GPIO_WritePin(RF_SW_CTRL2_GPIO_Port, RF_SW_CTRL2_Pin, GPIO_PIN_RESET);
        break;
    }
    case RBI_SWITCH_RFO_LP:
    {
        /*Turns On in Tx Low Power the RF Switch */
        HAL_GPIO_WritePin(RF_SW_CTRL1_GPIO_Port, RF_SW_CTRL1_Pin, GPIO_PIN_RESET);
        HAL_GPIO_WritePin(RF_SW_CTRL2_GPIO_Port, RF_SW_CTRL2_Pin, GPIO_PIN_SET);
        break;
    }
    case RBI_SWITCH_RFO_HP:
    {
        /*Turns On in Tx High Power the RF Switch */
        HAL_GPIO_WritePin(RF_SW_CTRL1_GPIO_Port, RF_SW_CTRL1_Pin, GPIO_PIN_RESET);
        HAL_GPIO_WritePin(RF_SW_CTRL2_GPIO_Port, RF_SW_CTRL2_Pin, GPIO_PIN_SET);
        break;
    }
    default:
        break;
}

Then, delete the other “#warning” lines in the file below each of these comments as we don’t need to change the existing code:

 /* USER CODE BEGIN RBI_Init_2 */
 /* USER CODE BEGIN RBI_DeInit_2 */
 /* USER CODE BEGIN RBI_GetTxConfig_2 */
 /* USER CODE BEGIN RBI_IsTCXO_2 */
 /* USER CODE BEGIN RBI_IsDCDC_2 */
 /* USER CODE BEGIN RBI_GetRFOMaxPowerConfig_2 */

Implementing a Minimal LoRaWAN Application

The application, as generated, will start up and make one attempt to join the LoRaWAN network. However, if this fails, it will basically halt.

To get the application to attempt to join again, add this code to LoRaWAN/App/lora_app.c

static void OnJoinRequest(LmHandlerJoinParams_t *joinParams)
{
    /* USER CODE BEGIN OnJoinRequest_1 */
    if (joinParams->Status == LORAMAC_HANDLER_SUCCESS)
    {
        APP_LOG(TS_OFF, VLEVEL_M, "App: OnJoinRequest - Success\r\n");
    }
    else
    {
        APP_LOG(TS_OFF, VLEVEL_M, "App: OnJoinRequest - error, try again\r\n");
        LmHandlerJoin(ActivationType, ForceRejoin);
    }
    /* USER CODE END OnJoinRequest_1 */
}

The app is now able to Join the LoRaWAN network. However, it may not show on the network as being active until it actually sends some data. This is also important as other features such as ADR (Automatic data rate) support piggybacks on packets which will adjust the node’s transmit power and data speed to minimise power use.

To send some data, add the following code to lora_app.c function SendTxData()

static void SendTxData(void)
{
    /* USER CODE BEGIN SendTxData_1 */
    sensor_t sensorData;
    EnvSensors_Read(&sensorData);
    LmHandlerAppData_t AppData = { 
        .Buffer = (uint8_t *)&sensorData, 
        .Port = LORAWAN_USER_APP_PORT,
        .BufferSize = sizeof(sensorData) 
    };
    if( LmHandlerSend(&AppData, false, false) == LORAMAC_HANDLER_SUCCESS )
    {
        APP_LOG(TS_OFF, VLEVEL_M, "App: Send Sensor Data\r\n");
    }
    else
    {
        APP_LOG(TS_OFF, VLEVEL_M, "App: Send had a problem\r\n");
    }
    /* USER CODE END SendTxData_1 */
}

This assembles a packet of dummy and actual sensor readings from sys_sensors.c/EnvSensors_Read() which includes MCU temperature and supply voltage.

  1. To be taken with caution as this well below the minimum of -40°C for the MCU itself, ref. product datasheet.
  2. The FREQ_HIGH pin is not actually used in this minimal implementation, but we allocate it to show it has a pre-assigned function in the RAK3172. It could still be used for other purposes as long as the circuit designer keeps in mind the pin will have either a pull-up or pull-down resistor on it.
  3. Reference LoRaWAN code has the output mode on both RF switch pins set to “Very High”. However, this is not an available option for PC13.
  4. Automatically powers down ADC when not in use – apparently big power saving
  5. Setting low frequency triggering is connected with Auto Off enabled – causes the ADC to be re-armed when new sample is done.
  6. This interrupt is needed to deal with a timer overflow that occurs roughly every 48 days. Under User Constants, add the following constants
  7. This prescaler is used to set the SPI baud rate to the radio which must be less than 16MHz. With a 48MHz clock, we get an SPI baud rate clock of 12MHz.
  8. The alternative option is to use “Bsp via ext settings”. This means using a “Board Support Package” and is more complex. If your application board will be used for many different projects, then it may be worth the effort to develop a BSP.