The Arduino board MKR1310 is the new revision of the MKR1300 board dedicated to LoRaWan. This board is a SAMD21 Arduino board with a Murata ABZ module based on a STM32 with an SX1276 transceiver. Basically a bit outdated and expensive modem now.
After using this board for some teaching project, it’s a good time to make a feedback about it as many things need to be improved on that board to get benefit of it.
A device not really ready to be used
When you receives the MKR1310, you don’t really have any documentation and the initial reflex is to search for library and exemple. You will find two of then MKRWAN v1 and MKRWAN v2. If you choose the wrong one it will not work… The reason is simple, each of the library comes with a different version of LoRaWAN firmware for the modem. Both are not compatible each other.
So it means that the first thing you need to do before using the board is to upload the right version of modem firmware into it. For doing this, go to the examples, select MKWANFWUpdate_standalone, load it and open the console view to load it. Once the load is completed, you can load another exemple and start using the board.
Basically, the MKRWAN v1 is using thee serial port for the communication with the modem firmware and the MKRWAN v2 is using the SPI for thee modem communications. Thee reason for using the SPI communication is related to the multiplexed lines between Serial and SPI avoiding to use the Flash and the LoRaWan modem concurrently.
Arduino is really not made for pro …
I’m using this board with my students to learn them some of the basic of IoT design, and at any step I felt like … how can we make something professional with an Arduino board as everything is always going wrong… let take some examples:
- A pro device needs to be setup with custom IDs including DEVEUI… but modem firmware does not support it
- A pro device needs to protect keys and storing them into the modem in this case is the best we can do… but the library JOIN command needs to have them
- A pro device needs to maintain a state / configuration over restart … but the device does not have NVM solution and running the 2Mb flash SPI is a mess
- A pro device needs a clean LoRaWan library … but the given library is just a s****y header file, all what we tell students to never do.
Fortunately, there are some solutions
Let’s fix the devEUI issue
At first, it’s good to understand why the DevEUI should be setup by the user, a first reason is that there is no reason to have it hardcoded. DevEui, JoinEUI and APPKey are composing a uniq identifier, so DevEUI on it’s own does not really have any meaning. The DevEUI are usually randomly generated by the network servers and it’s better to keep it random for protecting the IDs to make sure the device type can’t be identified from one of these IDs. That is for the security aspects. But if you take a look to the industrial aspects there are some other reason. The first one is related to the credentials creation process, usually you creates a batch of identifiers you give to the manufacturer to be loaded in the device, it’s better to be like this than creating a dependency or you will have a risk to stop your production line. If you need to create your IDs before making the device, it will be really simpler if you can decide what your DevEUI will be. The other reason is related to the product life cycle, when a device is replaced by another one (like a field loss or disfunction) you will make your life really simpler if you can reuse the same setting (it will avoid to create a new subscription if you have a public operator and it will allow to transparently continue the previous device data series). So, know you have the main reasons why having a fixed DevEUI is a conceptual error.
The MKR1310 is coming with a library where you can call the join function with a DevEUI:
virtual int joinOTAA(const char *appEui, const char *appKey, const char *devEui, uint32_t timeout);
So it sounds good… but even if the library can set the DevEUI, the available firmware whatever version it is, does not support the DevEUI modification (you can read the AppKey, stupid things in term of security, but you can’t write the AppKey … these developers never done a LoRaWAN device in my point of view).
The only way to fix this is to modify the modem firmware. The official firmware does not really seems to be maintained and respond to issues. So I had to go on an alternate firmware. This firmware supports the DevEUI set command and is compatible with the Arduino MKRWAN library v1.
The Join function needs the creadentials
Requesting the OTAA parameter in a join function is a mis-conception for a such architecture. The basic of the security is to avoid credential access. Basically the best is to have the credentials stored in the modem part and not make them accessible. But with the current implementation made by Arduino, if you use the library, you need to pass the credentials on Join. So the credential are stored in the SAMD21 and then transmitted transparently on the serial line. So they are really easy to access.
The good practice here is to store the credential only once inside the modem and then to call a join function without passing the credentials. These one are stored in the modem NVM so it works well.
This minimal modification to be made in the library is:
virtual int joinOTAA(const char *appEui, const char *appKey, const char *devEui, uint32_t timeout) {
YIELD();
rx.clear();
changeMode(OTAA);
if ( appEui != NULL ) set(APP_EUI, appEui); // vs set(APP_EUI, appEui);
if ( appKey != NULL ) set(APP_KEY, appKey); // vs set(APP_KEY, appKey);
if (devEui != NULL) {
set(DEV_EUI, devEui);
}
network_joined = join(timeout);
delay(1000);
return network_joined;
}
Now you can call the joinOTAA function without passing the credentials and your firmware doesn’t need anymore to contains these precious informations.
To complete the security aspects, it would be great to lock the appKey accesses from the modem to protect it from being read. This has been fixed thanks to the alternative firmware for the modem. I’ve made my own fork and the pull request is pending in the main one. You can find a version of it, directly upload-able into the MKR1310 on my github MKR1310 project.
With this firmware, protecting the AppKey is as easy as calling an AT function. Once done, you can’t go back until you erase the modem firmware. (this is not 100% secured, bypass may exist, I made it for teaching purpose at first).
# Lock the AppKey access
AT$APKACCESS
+OK
Later you can reset the access and clear the whole NVM configuration with command AT+FACNEW
save a state and some configuration
When you design an IoT device, you need somewhere to store some configuration setting. Some can be hardcoded but the best is to make them able to be modified remotely. It can be the transmission time of the activation of certain parts. It’s important to make this available remotely as it can help to fix issues like battery consumption or void potential bugs by disabling certain features. It’s always better to change a parameter than reflash devices on the field. When a parameter becomes something that can be override you need to store it in flash in a zone you can programmatically write. This is a NVM (Non Volatile Memory) zone.
One of the missing features in the SAMD Arduino system is a missing NVM zone. It’s possible to manage some space in flash as an eeprom zone but it’s quite complex to inside the Arduino environment. It should be a native feature within the SAMD library but it has not been designed like this and, as a consequence, you need to find different ways to to this.
The Murata chip used as a modem have 6KB of EEPROM into its STM32 device, some space is available into it and one of the way is to use that memory to store some information. So one of the solution was to add a new AT command to store and retrieve some data into the modem NVM. This command has been added in the alternate modem project (pending pull request) and can be loaded from my MKR1310 alternate ready to use firmware. This is an exemple of the command you can use. Currently only 4 bytes of data can be stored.
# Store 123 into NVM address 0
AT$NVM 0,123
+OK
# Read NVM address 0
AT$NVM 0
+OK=123
This solution is good for a small quantity of data, so why not using the embedded 2MB of flash we have on the board ? It would be really better wouldn’t be ?
Using the SPI FLASH with Serial modem
The problem of the embedded SPI flash is that the same lines have been used for SPI1 and LoRa Uart, as a consequence, when the LoRaWan modem is in use, the SPI lines can’t be used. The Arduino forum basically recommend to maintain the LORA_RESET line active to disable the modem and use the flash … that’s a funny way to say that a really bad design has been made. Concretely doing this means having to reconnect on LoRaWan every time you need to access flash witch is basically a stupid behavior. We need a better way for doing this.
The board have SAMD SPI1 connected to Murata ABZ SPI1 (why connecting two master ?!?), this is not a big issue as we can simply make sure that the ABZ lines will be Analog. But it’s also connecting the UART lines to the SPI lines. UART maintains a voltage on the TX lines, so the SPI lines will be jammed by this if not unset.
The solution has been to add a feature into the alternate modem to disable the UART when required, without having to reset the modem. I have created a new AT command to request UART to disconnect (AT$DISUART) then I use the so badly named “LORA_IRQ_DUMB” signal to request UART reconfiguration. So it is possible to deactivate the UART and use the SPI1 instead. So it can be use that way in a sketch:
// Configure the interface with the modem
// and request to deactivate the serial line
pinMode(LORA_IRQ_DUMB, OUTPUT);
digitalWrite(LORA_IRQ_DUMB, HIGH);
SerialLoRa.begin(19200);
while(!SerialLoRa);
SerialLoRa.println("AT$DISUART");
// Now the serial line is deactivated and SPI can be used
if ( !myFlash.begin(FLASH_CS,2000000,SPI1,SPI_MODE0) ) {
Serial.println("Failed to init Flash module");
while(true);
}
// After we can reconfigure the Serial line and request the UART
// to be reconfigured
SerialLoRa.begin(19200);
while(!SerialLoRa);
digitalWrite(LORA_IRQ_DUMB, LOW);
delay(100); // let some time to apply
// Now the modem can be used in a normal way
SerialLoRa.println("AT");
This is also using the modified firmware indicated previously above.