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:
- One Acme Systems Terra board
- Two IQRF modules (TR-52D)
- One IQRF programmer and debugger (CK-USB-04)
- One SIM card connector
- One Daisy-12 protoboard
- One 20cm flat cable with sockets for Acme Daisy Cabling System (FLAT-20CM)
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.
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?
Hi, this modules are great
Have u tested some modules on a mesh network? Is it simple to configure?
Best regards,
Vitor
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
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
Pingback: Wireless UART: how to connect your ARM based linux board | DoItWireless