Blog

iqrf

The microcontrollers almost always have one UART port, but haven’t (by default) the hardware needed to connect in wireless to other devices: to do this you can make a wireless UART. Using a couple of RF transceiver you can easy connect your Acme Systems Terra board to a PC or another device using a RF serial connection and Node. The Acme System Terra is a complete device based on the Aria G25 module System On Module (SOM) equipped with an Atmel AT91SAMG25.

What you need

To accomplish this task you need this components:

Prepare your hardware

Before to start you must prepare a simple Daisy board to connect an RF module to your Terra board. This is a very easy step: follow the table and the figure below.

DAISY-12-SIM
Pin ID Pin name Signal RF module
D10.1 3V3 Power supply C3
D10.2 PC22/TXD3 /dev/ttyS4 TXD C8
D10.3 PC23/RXD3 /dev/ttyS4 RXD C5
D10.10 GND Power supply C4

 

 

 

 

Install RF development environment

To load a firmware into an RF module you need the IQRF IDE: download from the official site and install in your PC.

NOTE: install IQRF IDE before connect your CK-USB-04 programmer.

Install firmware on RF module

The first RF module can be connected to the ttyS4 (or ttyS2) of the Terra board and must have a simple firmware that forward all data read from the serial port into RF buffer to transmit and viceversa. Microrisc provide an example with source code that implement this functionality (UART_LINK.c example). Edit this file as follow:

// *********************************************************************
//                            Aria UART Link
// *********************************************************************
//
// Intended for:
//   HW: - TR-52D
//   OS: - v3.02D
//
// Description:
//   This example works as UART (RS232) link. Received RF packet
//   is sent via UART and vice versa. UART receiving and transmiting use
//   MCU interrupt.
//   The bufferCOM is divided into two 32 B parts. First one works as a TX buffer
//   and second one as a circular RX buffer for UART data.
//   If the delay between RX UART data bytes is greater than 20 ms,
//   it it recognized as the end of the packet and then the packet is forwarded via RF.
//   This delay is measured by the Timer6. 
//
// File:     AriaUartLink.c
// Version:  v1.06                                   
// Revision: 20/04/2013
//
// Revision history:
//   v1.06: 20/04/2013  Added blinking led: the application is running
//   v1.05: 28/08/2012  Modified for OS 3.02D. Interrupt and Timer6 used.
//   v1.04: 19/06/2012  Comments slightly changed.
//   v1.03: 02/04/2012  Tested for baud rate 19200
//   v1.02: 26/03/2012  Modified for OS 3.01D, not tested for baud rate 19200
//   v1.01: 16/03/2011  Modified for OS 3.00.
//   v1.00: 02/06/2010  First release.
//
// *********************************************************************
#include "../../includes/template-basic.h"     // System header files

// *********************************************************************
                                            // Set UART baudrate
#define BD_19200                            // BD_19200, BD_9600, BD_4800
#define BUFFER_SIZE     32                  // DO NOT CHANGE! .. works only with 32

// *********************************************************************

// UART function prototypes
void openUART(void);
void closeUART(void);
void restartUART(void);
uns8 getTxStatusUART(void);
void sendDataUART(uns8 length);
uns8 getRxStatusUART(void);
uns8 getRxByteUART(void);
void copyRxDataUART(uns16 to, uns8 length);
void errorsRecoveryUART(void);
void userIntRoutine(void);
// *********************************************************************

// UART variables
uns8 TxData;                // Number of bytes to transmit
uns8 TxBytePtr;             // Pointer to the byte to be send
uns8 RxData;                // Number of received bytes
uns8 RxBufStartPtr;         // Circular buffer pointers
uns8 RxBufEndPtr;       
bit RxBufOverflow;          // RX buffer overflow flag
// *********************************************************************

void APPLICATION() {    
    openUART();
    
    startCapture();                 // Resets counter of ticks
    startDelay(50);                 // Start a delay (500ms in background)
    pulseLEDG();
    
    while(1) {
        if (!isDelay()) {
            pulseLEDG();
            startDelay(50);
        }
        
        toutRF = 5;

        if (TMR6IF) {                           // Gap between UART bytes was recognized
            TMR6ON = 0;                         // Timer off
            TMR6IF = 0;
            
            if (RxBufOverflow) {
                restartUART();
                continue;
            }
            
            DLEN = getRxStatusUART();
            copyRxDataUART(bufferRF, DLEN);
            pulseLEDR();
            PIN = 0;
            RFTXpacket();
        }
        
        if (checkRF(0)) {
            if (RFRXpacket()) {
                if (DLEN > BUFFER_SIZE)          // TX UART buffer has 32 B
                    DLEN = BUFFER_SIZE;
                    
                while (getTxStatusUART());      // Wait until previous packet is sent
                pulseLEDG();
                copyMemoryBlock(bufferRF, bufferCOM, DLEN);
                sendDataUART(DLEN);             // Send DLEN bytes from UART TX buffer
            }   
        }
    }    
}
// *************************************************************************

void openUART() {                       // Baudrate, 8N1
    TRISC.5 = 1;                        // Pin connected with RX
    TRISC.7 = 1;                        // RX input
    TRISC.6 = 0;                        // TX output
    BAUDCON = 0;                        // Baudrate control setup
                                        // Baudrate @ 8MHz, high speed
#ifdef BD_19200
    SPBRGL = 25;
#elif defined BD_9600
    SPBRGL = 51;
#elif defined BD_4800
    SPBRGL = 103;
#else
    SPBRGL = 51;                        // Default baudrate 9600 bd
#endif
    
    TXSTA = 0b00100100;                 // Async UART, high speed, 8 bit, TX enabled
    RCSTA = 0b10010000;                 // Continuous receiving, enable port, 8 bits
        
    RxData = 0;
    TxData = 0;
    TxBytePtr = 0;
    RxBufEndPtr = 0;
    RxBufStartPtr = 0;
    RxBufOverflow = 0;
                                        // Timer6 setting
    T6CON = 0x7B;                       // Prescaler: x64, Postscaler: x16, Timer: off
    PR6 = 39;                           // Period: cca 20ms for 8 MHz MCU clock
    TMR6IF = 0;
    
    RCIE = 1;                           // UART RX interrupt enable
    _enableUserInterrupt = 1;
}
//-------------------------------------------------------------------------

void closeUART(void) {                  
    _enableUserInterrupt = 0;
    TXEN = 0;
    CREN = 0;
    TXIE = 0;
    RCIE = 0;
}
//-------------------------------------------------------------------------

void restartUART(void) {
    _enableUserInterrupt = 0;
    CREN = 0;
    TXEN = 0;
    TXIE = 0;
    RCIE = 0;
    TxData = 0;
    RxData = 0;
    TxBytePtr = 0;
    RxBufEndPtr = 0;
    RxBufStartPtr = 0;
    RxBufOverflow = 0;
    CREN = 1;
    TXEN = 1;
    RCIE = 1;
    _enableUserInterrupt = 1;
}
//-----------------------------------------------------------------------------

void sendDataUART(uns8 length) {        // Starts sending data in background
    if (length > BUFFER_SIZE)
        length = BUFFER_SIZE;           // UART TX buffer has 32 B
    
    TxData = length;
    TxBytePtr = 0;
    TXIE = 1;                           // UART TX interrupt enable
}
//---------------------------------------------------------------------------

uns8 getTxStatusUART(void) {            // Returns number of bytes waiting to be send
    return TxData; 
}
//-------------------------------------------------------------------------

uns8 getRxStatusUART(void) {            // Returns number of received bytes
    return RxData; 
}
//-------------------------------------------------------------------------

uns8 getRxByteUART() {                  // Get first unread byte from circular RX buffer
    uns8 tmp;

    if (RxData) {
        GIE=0;
        tmp = readFromRAM(bufferCOM + RxBufStartPtr + BUFFER_SIZE);
        RxBufStartPtr = (RxBufStartPtr + 1) % BUFFER_SIZE;
        --RxData;
        RxBufOverflow = 0;
        GIE=1;
        return tmp;
    } else {
        return 0;
    }
}
//-------------------------------------------------------------------------

void copyRxDataUART(uns16 to, uns8 length) {
uns8 i, tmp;

    if (length > BUFFER_SIZE) {
        length = BUFFER_SIZE;
    }

    for (i = 0; i < length; i++) {
        tmp = getRxByteUART();
        writeToRAM(to + i, tmp);
    }
}
//-------------------------------------------------------------------------

void errorsRecoveryUART() {             // OERR and FERR bits recovery - see PIC datasheet
    if (OERR) {                         // Overrun recovery
        CREN = 0;
        CREN = 1;
    }

    if (FERR) {                         // Framing error recovery
        FERR = 0;
    }
}
// ***********************************************************************

#pragma origin 0x3F00                   // This address must not be changed
void userIntRoutine() {                 // User interrupt service routine
    if (RCIF) {                         // Something was received via UART
        errorsRecoveryUART();
        FSR0 = bufferCOM;
        FSR0 = FSR0 + (RxBufEndPtr + BUFFER_SIZE);
        setINDF0(RCREG);
        RxBufEndPtr = (RxBufEndPtr + 1) % BUFFER_SIZE;
        
        if (RxData < BUFFER_SIZE) {
            ++RxData;
        } else {                        // Buffer overflow
            RxBufStartPtr = (RxBufStartPtr + 1) % BUFFER_SIZE;
            RxBufOverflow = 1;
        }
        
        TMR6 = 0;                       // Timer reset
        TMR6ON = 1;                     // Timer on
    }   
    
    if (TXIF && TxData) {               // There is still data to send and UART peripheral is free
        FSR0 = bufferCOM + TxBytePtr;
        TXREG = getINDF0();             // Copies data from bufferCOM to TXREG
        ++TxBytePtr;
        
        if (--TxData == 0) {
            TXIE = 0;                   // No more data to send, clear interrupt flag
        }
    }
}
// *********************************************************************

Now put your first RF module into the programmer and connect it to your PC, open your IQRF IDE and follow the instruction below (see official IQRF help for a detailed instructions):

  • create a new project
  • edit the module settings according your module
  • attach the file above
  • compile
  • upload

Now remove the RF module and put it into the homemade Daisy module and connect it to your Terra board using the D10 connector (remember to insert the RF module before connect Daisy module).

The second RF module must have a firmware that send an RF packet with desired data to the RF module connected to the Terra board and/or viceversa according your needs. To easy test the functionality, you can use another firmware example (E03-TR.c) and edit it as follow:

// *********************************************************************
// *                       Aria Remote Link                            *
// *                        RF transceiver                             *
// *********************************************************************
// Example of RF transmiter/receiver. Suitable for a PC link.
//
// Intended for:
//   HW: - TR-52D
//   OS: - v3.02D
//  
// Description:
//   - This program applied in two kits is a bidirectional RF-SPI interface.
//   - Received RF data is sent via SPI and vice versa. For sending and
//     receiving SPI data e.g. the IQRF IDE Terminal can be used
//     (See IQRF IDE Help).
//   - Received SPI data is sent via RF.
//   - PIN should be updated in case of bidirectional RF communication
//     before every RF transmission.
//
// File:    AriaRemoteLink.c
// Version: v1.03                                   Revision: 20/04/2013
//
// Revision history:
//   v1.03: 20/04/2013  Added blinking led: the application is running
//   v1.02: 28/08/2012  Tested for OS 3.02D
//   v1.01: 14/06/2012  Tested with TR-54D
//   v1.00: 07/03/2012  First release
//
// *********************************************************************
#include "../includes/template-basic.h"

// *********************************************************************
void APPLICATION() {
    enableSPI();                    
    toutRF = 5;

    startCapture();                 // Resets counter of ticks
    startDelay(200);                // Start a delay (2s in background)
    pulseLEDG();
    
    while (1) {                     // Main cycle (perpetually repeated)
        if (!isDelay()) {
            pulseLEDG();
            startDelay(200);
        }

        if (checkRF(5)) {           // RF signal detection (takes 1ms)
            if (RFRXpacket()) {     // If anything was received
                pulseLEDG();        // LED indication
                copyBufferRF2COM(); // Copy received RF data from bufferRF to bufferCOM
                startSPI(DLEN);     //  and send it via SPI
            }
        }
        
        if (getStatusSPI()) {       // Update SPIstatus, check SPI busy
                                    // SPIpacketLength: data length
             continue;              // Wait until message is picked up
        }
        
        if (_SPIRX) {               // Anything received?
                                    // Yes:
            if (_SPICRCok) {        // CRCM matched?
                                    // Yes:
                DLEN = SPIpacketLength;
                copyBufferCOM2RF(); // Copy received SPI data from bufferCOM to bufferRF
                PIN = 0;
                RFTXpacket();
                pulseLEDG();        // LED indication
            }

            startSPI(0);            // Restart SPI communication
        }
    }
}

// *********************************************************************

Now put this RF module into the programmer and connect it to your PC, open your IQRF IDE and follow the instruction below (see official IQRF help for a detailed instructions):

  • create a new project
  • edit the module settings according your module
  • attach the file above
  • compile
  • upload

Leave this module plugged into the programmer and see the results into the terminal window.

Install software on Terra board

Last task: install Node.js using this instructions. Open your terminal and type:

mac: ~$ ssh root@debarm-ip

Linux debarm 2.6.39 #9 Sat Apr 13 09:59:50 UTC 2013 armv5tejl

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.

debarm:~# mkdir serial
debarm:~# cd serial
debarm:~/serial# touch serial.js
debarm:~/serial# npm install serialport

Edit the created serial.js file:

var SerialPort = require('serialport').SerialPort;
/**
 * /dev/ttyS4 -> Terra D10 connector
 * /dev/ttyS2 -> Terra D13 connector
 */
var serialPort = new SerialPort('/dev/ttyS4', {
    baudrate: 19200,
    databits: 8,
    stopbits: 1,
    parity: 'none'
});
serialPort.on('open', function() {
    console.log('open');
    serialPort.on('data', function(data) {
        console.log('data received: ' + data);
    });
    serialPort.write("Welcome Aria UART RF connected!", function(err, results) {
        console.log('total written bytes ' + results);
        console.log('err ' + err);
    });  
});

Run your test program:

debarm:~# node serial.js

After a few seconds you see in your terminal:

open
total written bytes 31
err undefined

and your IQRF IDE shows the sent message (Welcome Aria UART RF connected!).
Enjoy!




About Marcello Gesmundo

I'm the founder of Yoovant company. I'm an engineer and an artist: what could be better than combine the technologies with the arts?

4 Comment(s)
  1. Vitor Andre April 30, 2013 at 03:11

    Hi, this modules are great
    Have u tested some modules on a mesh network? Is it simple to configure?

    Best regards,
    Vitor

    • Marcello Gesmundo April 30, 2013 at 09:23

      Hi Vitor,
      yes this module supports IQMESH technology and it is more simple than other mesh technologies that I’ve tried. You can use an RF module as coordinator connected to a microcontroller: I publish another example for this configuration. Stay tuned!
      Kind regards,
      Marcello

  2. Vitor Andre April 30, 2013 at 16:04

    Hi, tanks for information Im waiting for modues to start testing them in iqmesh configuration.
    Im planning to develop some kind of RPC for making easy communication on network with many nodes.
    The coordinator iqrf module is connected to ariag25 serial and also using nodejs.
    For example nodejs sends by serial the command REM10:6,1 this is interpreted by the coordinator module to send data to module #10 in network for output 6 go to level high.
    Or for example command REM15:somefunction,3 This will remote call on node #15 the function somefunction(3) with argument variable 3 to execute some task and return confirmation or return some value for coordinator.

    This kind of RPC protocol should make a standard way to comunicate to other modules by a simple and easy way.

    Best regards,
    Vitor

  3. Pingback: Wireless UART: how to connect your ARM based linux board | DoItWireless

Leave a Reply to Vitor Andre Cancel reply

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>