Getting started with ST Murata LoRaWan board

ST Micro-Electronics is providing a development board with a Murata CMWX1ZZABZ-091 chip. This device is a module containing a STM32L0 chip (192Kb of Flash / 20Kb of RAM) associated with a Semtech SX1276 radio chip. This module can be used as a SoC for developing LoRaWan IoT devices. The Semtech chip is also capable of Sigfox. This module is a bit expensive but it is actually the one allowing LoRaWan and Sigfox communication in any of the RCZ zones.

Murata LoRaWAn / Sigfox architecture

The LoRaWan stack for STM32 can be found on the ST Microelectronics website. The software package is about 480MB unzip even if, for real, only a couple of files are needed. Basically this package could contain the most important file to getting started: an ioc (CubeMx project) file for the Murata device, but it is not.

The following diagram represents the Murata Soc Architecture:

There are two types of STM32 chips in the SoC. STM32L072 and STM32L082. This last version have a hardware AES encryption module. Both have 192BK flash, 6KB EEprom and 20KB RAM. They both have a 32MHz TCXO and a 32,768KHz external quartz with +/- 20ppm for measuring time. A secure element (STSAFE) can be added as an option inside the SoC for large volume.

The external wiring for LoRaWan and Sigfox is a bit different.

Spoiler: a complete implementation is available

Base on Disk91 IoT SDK a working example implementing Murata device with the Semtech LoRaWan stack is available on my gitHub. You can clone the Murata CMWX1ZZABZ example and follow the README.md steps to make it working.

The following chapters provide details on the implementation & configuration. It lets you recreate the example from scratch.

Create a basic project from Cube-MX

Cube MX is the STM32 environment to create your project skeleton and configure the STM32 hardware. You can launch it and select B-L072Z-LRWAN1 via the Board Selector.

The clock configuration used by the demo code is a HSI source (16MHz). The PLL is used with a X6 multiplier and /3 division to reach 32Mhz PLLCLK. This clock signal is used for SYSCLK. The RTC clock can be sourced from the LSE clock based on the 32.768KHz Crystal

The UART2 is connected to STLINK for getting a serial log on the USB communication.

Leds and interrupt are connected the following way:

  • LED1 – PB5
  • LED2 – PA5
  • LED3 – PB6
  • LED4 – PB7
  • BUTTON – PB2

The other pins are automatically setup by cube MX with the corresponding SX1276 pins reference

Setup Disk91 IoT SDK

The Iot SDK is an open-source SDK I’m working on. It purpose is to propose an SDK supporting various MCU and various communication protocols and interfaces. I’ve implemented the ST / Semtech code for supporting the Murata chip is an easier and expandable way.

The SDK includes low-power feature, time management, gpio integration… A minimal setup is required to make it working correctly. On top on the previous configuration in CubeMX, you need to setup different components.

  • RTC :
    • Async_prediv is 127 and Sync_prediv is 255
    • ClkSource activated
    • Calendar activated
    • Internal WakeUp activated
    • The clk configuration can be LSI or LSE based on your configuration
    • The RTC/NVIC Interrupt is activated.
    • Wake-up => RTCLK/16
  • GPIO:
    • Activate the different NVIC interrupt.
    • The direction and detailed setting will be override in the driver implementation. You only need to correctly configure the Leds & Buttons.
  • SYSCLK
    • Activate Sysclk

You can directly setup the overall configuration using this CubeMX ioc file for STM32/Murata.

Initialize code structure

Once you have terminated the CubeMX configuration, you can generate the code skeleton. I recommend the following setting for the best integration with Disk91 IoT Sdk.

Once the project generated you need to include the Disk91 Iot Sdk into your project. You just need to copy the file structure into a ItSdk folder into your project. The README.md is indicating the different setting you have to do in the IDE to include these files into the compilation path.

Configure the Disk91 IoT SDK

The IoT framework configuration is based on different configuration file. The configuration file allows to activate / unactivate features and set the different key elements like the LoRaWan address to be used. In the first published version, all the configuration for LoRaWan are static, at compilation time. Future version will manage dynamic reconfiguration and eeprom storage instead of hard coded values (stay tuned). For a LoRaWan demonstration you need to copy and initialize two configuration files:

  • project_path/Core/Inc/it_sdk/config.h : this files is the main configuration file. It contains the overall SDK configuration and declare the module to be included. Like LoRaWan. An example for a working configuration for the Murata is on github. The config.h template is provided with the IoT_SDK in the Inc/it_sdk/config.h.template file.
  • project_path/Core/Inc/it_sdk/configLoRaWan.h: this file is the LoRaWan configuration file. It contains the LoRaWan global configuration and the different drivers configuration. An example is accessible on github. In this file you will setup the LoRaWan join method, EUI and Keys needed for the authentication. You can also define the frequency plan.

That’s all you need to do for the configuration. You have some of the CubeMx generated files to modify as indicated in the IoT SDK Readme.md file. These modification will integrate the IoT SDK in the generated code with a minimum of modification to let you modify the CubeMX configuration without impacting your code. The modifications are concerning the following files:

  • main.c : integrate the IoT SDK calls on setup & loop.
  • gpio.c : add the gpio reconfiguration after wake-up
void stm32l_lowPowerRestoreGpioConfig() {
	  //GPIO_InitTypeDef GPIO_InitStruct = {0};

	 /* GPIO Ports Clock Enable */
	  __HAL_RCC_GPIOA_CLK_ENABLE();
	  __HAL_RCC_GPIOB_CLK_ENABLE();
	  __HAL_RCC_GPIOC_CLK_ENABLE();
	  __HAL_RCC_GPIOH_CLK_ENABLE();
	
	  /* EXTI interrupt init*/
	  HAL_NVIC_SetPriority(EXTI0_1_IRQn, 0, 0);
	  HAL_NVIC_EnableIRQ(EXTI0_1_IRQn);

	  HAL_NVIC_SetPriority(EXTI4_15_IRQn, 0, 0);
	  HAL_NVIC_EnableIRQ(EXTI4_15_IRQn);
}
  • stm32l0xx_it.c : add a missing EXTI handler
void EXTI4_15_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI4_15_IRQn 0 */

  /* USER CODE END EXTI4_15_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4);
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);
  /* USER CODE BEGIN EXTI4_15_IRQn 1 */
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_5);

  /* USER CODE END EXTI4_15_IRQn 1 */
}

Create your code

Then you need to create a project_main.c file in your Core directory with the following structure:

#include <it_sdk/config.h>
#include <it_sdk/itsdk.h>
#include <it_sdk/time/time.h>
#include <it_sdk/logger/logger.h>
#include <it_sdk/lorawan/lorawan.h>


//=================================================
// Setup
void task();

void project_setup() {
	log_init(ITSDK_LOGGER_CONF);
	log_info("Booting \r\n");

	// Init LoRaWan stack
	static itsdk_lorawan_channelInit_t channels=ITSDK_LORAWAN_CHANNEL;
	#ifdef ITSDK_LORAWAN_CHANNEL
	   itsdk_lorawan_setup(__LORAWAN_REGION_EU868,&amp;channels);
	#else
	   itsdk_lorawan_setup(__LORAWAN_REGION_EU868,NULL);
	#endif
	  itdt_sched_registerSched(30000,ITSDK_SCHED_CONF_IMMEDIATE, &amp;task);
}

// ================================================
// What to do

void send_callback(itsdk_lorawan_send_t status) {
	switch ( status ) {
	case LORAWAN_SEND_ACKED:
		break;
	case LORAWAN_SEND_SENT:
		break;
	default:
		break;
	}
}

void task() {
   uint8_t t[20] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};

   if ( !itsdk_lorawan_hasjoined() ) {
      if ( itsdk_lorawan_join_sync() == LORAWAN_JOIN_SUCCESS ) {
		
      } else {
	
      }
   } else {
	itsdk_lorawan_send_async(
			t,
			16,
			1,
			__LORAWAN_DR_5,
			LORAWAN_SEND_CONFIRMED,
			ITSDK_LORAWAN_CNF_RETRY,
			send_callback
	);
   }
   log_info("time is %d\r\n",(uint32_t)itsdk_time_get_ms());
}

/**
 * Project loop may not contain functional stuff
 * Keep in this loop only really short operations
 */
void project_loop() {
	itsdk_lorawan_loop();
}

This code basically setup the communication by joining the network and then fire a communication with ack every 30 seconds.

In this example you can see two ways to interact with the lorawan driver. It can be synchronously. In this case the function will return only once the action is completed, returning a status. The other way is asynchronous: the driver shortly returns. The execution will continue in parallel in the itsdk_lorawan_loop. This way the device can go to sleep mode during the wait phase. In this mode a callback function is called on status change.

You can choose on mode or the other and mix the two.

This entry was posted in Hardware and tagged , , , . Bookmark the permalink.

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.