M-Bus ( Meter-Bus ) communication is a European Standard for remote readings of gas, water or electricity meters. M-BUS RF click uses the Telit ME70-169 with its' own protocol stack already installed on the module. We have written a library to use this click for very easy sending and receiving of data, and anything else possible with this module.
M-Bus Communication Modes
Devices that communicate with wireless M-Bus modules are classified as either meters or 'other' devices. Meter devices transmit utility consumption data while 'other' devices ( also known as concentrators ) are in charge of collecting this data and can optionally send commands to meters. The six different M-Bus modes are as follows:
• Mode S ‘Stationary’
• Mode T ‘frequent Transmit’
• Mode R2 ‘frequent Receive’
• Mode C ‘Compact’
• Mode N ‘Narrowband VHF’
• Mode F ‘Frequent receive and transmit’
Mode S
The bit rate for radio communication is 32.768 kbps. The following two sub-modes are defined:
• Mode S1 operates exactly as Mode T1 (unidirectional spontaneous transmission) but uses a different radio link.
• Mode S2 is similar to Mode T2 (meter sends a frame and waits for a response during a short interval) but also with a different physical link.
Mode T
In mode T, the meter sends spontaneously data, either periodically or stochastically. Frame transmission from meters to other devices uses a bit rate of 100 kbps, while communication in
the opposite direction is carried out at 32.768 kbps.
• In Mode T1 the meter doesn’t care if any receiver is present or not. The meter sends data and returns immediately in power-save mode without waiting for a response. This is a unidirectional communication.
• In Mode T2 the meter sends its data and stays awake during a short time immediately after transmission to listen to a possible response frame. If no response is received, the meter returns in power-save mode. If a response is received, then a bidirectional communication link is opened between meter and concentrator.
Mode R2
In Mode R2 the meter doesn’t send spontaneously data. The meter wakes up periodically in Rx mode and waits for a wakeup frame received from concentrator. If no frame is received, the meter returns in power-save mode. If a valid wakeup frame is received, a bidirectional link is then opened between meter and concentrator. The bit rate used in this mode is 4.8 kbps.
Mode C
This mode is similar to mode T but uses a different encoding scheme (NRZ); communication from meters to other devices is at 100 kbps, while in the opposite direction a 50 kbps bit rate is used. Two sub-modes are defined, C1 for unidirectional communication from meters to other devices and C2 for bidirectional communication.
Mode N
It uses narrowband communication in the 169 MHz frequency band; the two sub-modes N1 and N2 are for unidirectional and bidirectional communication, respectively. The standard Wireless M-Bus defines different channels, with different bit rates and modulation types, as listed below:
• Channel 1a: 4.8 kbps, GFSK modulation
• Channel 1b: 4.8 kbps, GFSK modulation
• Channel 2a: 2.4 kbps, GFSK modulation
• Channel 2b: 2.4 kbps, GFSK modulation
• Channel 3a: 4.8 kbps, GFSK modulation
• Channel 3b: 4.8 kbps, GFSK modulation
• Channel 0: 19.2 kbps, 4-GFSK modulation
Additionally, the CIG interchangeable Task Force defines that channels 2a and 2b can be accessed at 2.4 kbps or 4.8 kbps.
Mode F
It is a bidirectional mode operating at 2.4 kbps in the 433 MHz frequency band; communication can be initiated by either the meter (similar to Mode T2) or the concentrator
(using a wakeup frame as is done in Mode R2).
Sending Optional Data
By default, the protocol stack only expects the data from the user, and uses a timeout to indicate when you are finished sending data. This works completely fine, but there are also other fields you can optionally send yourself. All of these options can be enabled or disabled using mbus_set_serial_tx_format( serial_tx_format_t format ) . Here is a graph showing the affects and descriptions of the optional fields:
Arguments for setting serial TX format can be "OR" together like this, mbus_set_serial_tx_format( LENGTH_TX | CI_FIELD | A_FIELD ) . Here is a list of the enums used for the function:
- Wakeup - Wakeup pin on this module is not connected, so wakeup enum has no affect.
- Length - LENGTH_TX
- C Field - C_FIELD_TX
- M Field - M_FIELD_TX
- A Field - A_FIELD_TX
- CI Field - CI_FIELD_TX
- Data - Always enabled
Receiving Optional Data
While receiving data, by default the data field is all that is enabled. For using MikroE library for the MBUS RF click, you must enable the length field so that the ISR( Interrupt Sub Routine ) knows what to expect when it receives the first byte of data. Like the transmitting of data, you can enable other fields by using mbus_set_serial_rx_format( serial_rx_format_t format ) .
Just like the transmitting format, arguments can be sent by "OR"ing them together. Here is the list of enums used for receiving format:
- Wakeup - Wakeup pin on this module is not connected, so wakeup character has no affect.
- Length - LENGTH_RX
- C Field - C_FIELD_RX
- M Field - M_FIELD_RX
- A Field - A_FIELD_RX
- CI Field - CI_FIELD_RX
- Data - Always enabled.
- LQI Field - LQI_RX
- RSSI Field - RSSI_RX
- FreqOffset - FREQ_OFFSET_RX
Operating Modes
Before you can do any kind of configuration or communication, you must set up your UART interrupt for your specific MCU. In the interrupt vector you must place the ISR function mbus_rx_isr( char rx_input ). Here is an example of an interrupt setup for the ARM STM32F107VC...
void setup( void ) { RXNEIE_USART3_CR1_bit = 1; /**< Enables interrupts for USART3 */ NVIC_IntEnable( IVT_INT_USART3 ); EnableInterrupts(); } void LO_RX_ISR() iv IVT_INT_USART3 ics ICS_AUTO { tmp = USART3_DR; mbus_rx_isr( tmp ); /**< Send character to mbus ISR function */ }
Configuration
One of two options must be used when using M-Bus commands. AT mode is for configuring the module and OP mode is for sending/receiving data from another M-Bus. To configure the M-Bus use the mbus_at_init( void ) function. Once in this mode all configuration commands will be valid, as well as register reading / writing. Here is an example of setting up the M-Bus for configuration and setting serial receiving format to receive the length field.
//Initialize Conifguration Mode mbus_at_init(); //Setup Rx Format mbus_set_serial_rx_format( LENGTH_RX );
To read from a register you can use a buffer like this...
uint8_t buffer[20] = { 0 }; //Get firmware bootloader mbus_get_firmware_bootloader_vers( buffer );
You can also use a buffer for writing to a register like this...
uint8_t new_meter[10] = { 0, 1, 2, 3, 4, 5 }; //Set Meter Address mbus_set_meter_address( new_meter );
Operating ( M-Bus to M-Bus Communication )
Before communicating from one M-Bus module to another, you must initialize OP mode like this:
//Initialize Operating Mode mbus_op_init();
M-Bus to M-Bus communication is very easily done with a sending and receiving struct that are organized like this..
typedef struct { uint8_t length_field; uint8_t c_field; uint8_t m_field[2]; uint8_t a_field[6]; uint8_t ci_field; uint8_t data_field[245]; uint8_t lqi_field; uint8_t rssi_field; uint8_t freq_offset_field; } receive_frame_t; typedef struct { uint8_t length_field; uint8_t c_field; uint8_t m_field[2]; uint8_t a_field[6]; uint8_t ci_field; uint8_t data_field[245]; } transmit_frame_t;
Sending
To send data, use the transmit_frame_t struct. Fill the data_field with the data you'd like to send along with any other fields you may have enabled. As a reminder, this is how to set another field to enabled, for example the length field: mbus_set_serial_tx_format( LENGTH_TX ) . After the data field and any other applicable fields are filled, use mbus_send_frame( transmit_frame_t *transmit_frame, uint8_t data_len ) to send your data over the serial link. The Telit module uses its' firmware to parse through your data and based on the enabled fields, sends this packet over the RF link to other M-Bus modules on the same frequency. Here is an example of sending a sentence over the M-Bus RF link using sprintf and strlen...
sprintf( transmit_frame->data_field, "This is the %dst frame of data.", 1 ); /**< Fill data field with a simple sentence */ transmit_frame->length_field = strlen( transmit_frame->data_field ); /**< Use strlen to give the length field correct length */ mbus_send_frame( transmit_frame, 1 ); /**< Using length field for TX format, so no length needed */
Note: If you are not using the length field of the transmit frame, you must give the mbus_send_frame function the length of your data field.
Receiving
When receiving data you must ensure that the length field is included in the receiving format of the frame like this: mbus_set_serial_rx_format( LENGTH_RX ) . When the ISR finds that a complete frame from another M-Bus has been received, a flag called bool my_receive_flag will be set to true so that the user knows when to use mbus_receive_frame( receive_frame_t *receive_frame) . A user uses this flag to pole for received frames. Here is an example...
while( 1 ) { if( my_receive_flag ) //If ISR has found complete frame { mbus_receive_frame( receive_frame ); //Send your frame to be populated with data parse_frame( receive_frame ); //User-Defined function to use data from frame } }
Encryption / Adding, Editing and Removing Registered Meters
Now that we understand how to use the M-Bus for configuring and operating, let's dig a little bit deeper and talk about encryption. The Telit module can encrypt and decrypt Wireless M-Bus frames to provide secure communication between nodes. Both DES and AES-128 algorithms as defined in EN 13757-3:2012 are supported, as well as AES-128 with Counter Mode as defined in EN 13757-4:2013.
Concentrator devices can send encrypted frames to (and receive encrypted frames from) any of the registered meters; to enable encryption for communication with a given meter, manufacturer ID, address and key (DES or AES-128) of the meter must be initialized using this function:
status_t mbus_add_edit_meter( meter_options_t options, uint8_t *meter_address, uint8_t *encrypt_key, encryption_type_t enc_mode, uint8_t *manufac_id )
The user must send a meter option of type meter_options_t, the address of the meter they'd like to register, the encryption key, encryption mode( AES or DES ), and an optional maufacturer ID for the module being registered. Here is an example of adding a meter with no filter, an address of 0 1 2 3 4 5( for example purposes ), an encryption key, encryption type, and no manufacturer ID...
uint8_t new_meter[10] = { 0,1,2,3,4,5 }; uint8_t encrypt_key[17] = { 5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80 }; //Add New Meter mbus_add_edit_meter( DONT_FILTER, new_meter, encrypt_key, AES_MODE, NULL );
Hardware Flow Control
To manage overlapping of sending / receving data from the module to the user or M-Bus to M-Bus communication, Telit has implemented a hardware flow control. The RTS and CTS pins are used to check when the module is busy and cannot receive data, or to pole if another M-Bus module is ready to receive more data. Here is a diagram to better explain how the connections happen from your MCU to the Telit M-Bus module.
In both configuration mode and data mode, flow control on the serial port is operated via the RTS pin, which is de-asserted (logic level 1) when the module is unable to receive bytes (e.g.
when processing an AT command or a serial frame) and re-asserted (logic level 0) when new bytes can be received. The CTS pin is checked after a frame is received from radio and before sending it on the serial link. If CTS is de-asserted, only one frame is stored (the oldest one).
Source code can be found on either Libstock or Github.
Summary
Meter bus is a new European standard for reading all types of consumption meters, sensors and actuators. With this click and library provided, remote reading and collection of data from other meters is a breeze! With capabilities such as individual addressing of meters, encryption and a 20km range this click is perfect for the collection of any kind of data you need.