Shopping Cart

Posts

Playing Xbee. Part 1 - First impression.

Xbee coordinator

Xbee coordinator

Couple of days ago, I picked a pair or Xbees at Sparkfun. The plan is to build low power sensor platform using PICs, Zigbee radios, and Linux. In this article, I’m sharing my experience in building with Xbees.

The BOM includes two Xbee 2.5 RPSMA radios, Xbee USB explorer, Xbee breakout, PIC18F4520 microcontroller, and a breadboard. The code is written in C18 and built in MPLAB. Project files are available in download section.

Even though it is (presumably) possible to get two Xbees talk without any configuration, I decided not to do it. First, the firmware was old; second, I’m planning on having more than two radios. In addition to that, new stack supports firmware upgrades over the air. I downloaded X-CTU and upgraded my radios to Xbee ZB; one became a coordinator( pictured on the right ), the other one a router.

I also followed a procedure outlined in “Quick start” guide for 2.5 and performed range test to make sure radios can see each other.

For the purpose of this demonstration, I made PIC part of the setup as simple as possible. The schematic diagram of Xbee to PIC connections contains MCU itself and 10K pull-up resistor. The MCU is clocked by 8MHz internal oscillator. The USART speed is set to 9600bps. The second radio is left installed in USB explorer board and connected to Linux machine. On my Ubuntu 8.04 server I can see it as /dev/ttyUSB0. To communicate to this device I use minicom terminal emulator. Similar setup can be made on Windows; my favorite terminal emulator for this platform is Putty.

Xbee terminates a line with single CR (carriage return, or return cursor to position number one). By default, terminal emulator program won’t add LF ( linefeed, or move cursor to the next line); as a result, new output gets printed over an old one. Most terminal emulator programs has a setting for this very case called “Add linefeed” in minicom or “implicit CR in every LF” in Putty. Output of my code is also formatted this way – no linefeeds.

Flow control is essential. Xbee’s serial engine is slower than PIC; it is very easy to fill Xbee’s receive buffer and start losing data. Usual approach is to pace the transmission rate using delays; however, this also increases time when MCU is awake and, consequently, power consumption. On the other hand, using flow control signals it is possible to put MCU to sleep during CTS high (as you can see on this logic analyzer trace, given constant trasmission, CTS goes high for quite some time and we can make waiting time even longer relative to sending time by increasing the port speed).

Let’s talk about pins. I always define PIC pins that I use in a header file called project_config.h. Later I use functional names given to pins instead of pin names. For example, CTS is defined in project_config.h as:

#define CTS            PORTDbits.RD0
#define CTS_TRIS    TRISDbits.TRISD0

This way, if you decide to use some other pin as CTS, you only need to change these two lines and recompile.

The code consists of initialization, 1ms timer interrupt, serial functions and interrupts, and CLI task, which runs in endless loop. Initialization is one-time hardware setup – configuring port direction, timer3, CCP2, USART, and interrupts. Serial routines are borrowed from Fred Eady’s numerous publications in “Circuit Cellar” and his 2 microcontroller communications books. I just ported them from Hi-Tech C to C18 and added CTS flow control. They are described in great detail in Networking and Internetworking with Microcontrollersbook. Here, I just want to point to one detail. There are two places where we can check on CTS. The first place is a sendchar() function on line 8:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* send character                                                           */
/* blocks program execution while txbuf is full or CTS is high              */
/* use with caution                                                         */
BYTE sendchar(BYTE data)
{
  BYTE tmphead;
  tmphead = ( USART_Tx_head + 1 ) & USART_TX_BUF_MASK;  // calculate buffer index
  while ( CTS );                                        // wait for CTS to go low
  while ( tmphead == USART_Tx_tail );                   // wait for free space in buffer
  USART_Tx_buf[tmphead] = data;                         // store data in buffer
  USART_Tx_head = tmphead;                              // store new index
  PIE1bits.TXIE = 1;                                    // enable TX interrupt
  return data;
}

This works well if program is not transmitting a lot of data all the time.

The second place where CTS can be checked is serial transmit interrupt routine in line 16 (commented out). Since transmit interrupt flag won’t be cleared, the program will constantly go in and out of interrupt routine until CTS de-asserts.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#pragma interruptlow lowPriorityISR
void lowPriorityISR(void)
{
 BYTE data,tmphead,tmptail;           //USART vars
/* USART handler start */
    if(PIR1bits.RCIF) {
        data = RCREG;                                                   // read the received data 
        tmphead = ( USART_Rx_head + 1 ) & USART_RX_BUF_MASK;            // calculate buffer index 
        USART_Rx_head = tmphead;                                        // store new index 
        if ( tmphead == USART_Rx_tail ) {
        // ERROR! Receive buffer overflow 
        }
        USART_Rx_buf[ tmphead ] = data;                                 // store received data in buffer 
  }
    //? need to check for Tx IF
    if( TXSTAbits.TRMT /* && ( CTS == 0 ) */) { 
                                                                        // check if all data is transmitted  
        if ( USART_Tx_head != USART_Tx_tail ) {                                     
            tmptail = ( USART_Tx_tail + 1 ) & USART_TX_BUF_MASK;        // calculate buffer index  
            USART_Tx_tail = tmptail;                                    // store new index  
            TXREG = USART_Tx_buf[ tmptail ];                            // start transmition  
        }
        else {
            PIE1bits.TXIE = 0;         // disable TX interrupt  
        }
    } 
/* USART handler end */
}

Xbee console

Xbee console


CLI, which runs from the main loop, checks for incoming character. If there is one, CLI branches according to the character. If no character was entered, CLI returns to the main loop and gets started again. CLI is a state machine; it remembers where it last returned from and starts from the same place next time. The menus are empty except for “Show” menu item 1; other menus are just placeholders.

Finally, I’d like to show you how the end result looks like. Build both ends of the link as described, then build and run the PIC software. If everything is correct, you will see the banner and prompt. Press “1″ and prompt will change. Press “1″ again and the software will print current uptime.

I will be building several different sensors based on this setup. They will be posted here as soon as they are operational. In my next article I talk about next steps in Xbee sensor development – taking measurements and switching between Xbee command and data modes.

Good luck with this project. Let me know if you have any questions or issues.

Oleg.

Related posts:

  1. Xbee microcontroller board.
  2. Playing Xbee. Part 4 – API.
  3. Playing Xbee. Part 3 – Measure and send.
  4. Playing Xbee. Part 2 – Command mode.

27 comments to Playing Xbee. Part 1 – First impression.

  • radu022003

    hi, please help me with xbee, i’m also interfacing xbee with 18F, 18f4550.
    I’m connected with xbee only with rx, tx and gnd. If i send data from :
    pic ->xbee ))))))xbee->pic i got huge lag. i tryed to send 0 to 9(with 1s delay between chars) in a for loop from one pic to another and i receive first 9 chars ok, but after that it stops and receiving 3-4 bytes bulk, and i lose data. i can give you the schematic, code, everything you need, please help me.

    • Have you tried to use my code? You shouldn’t get much lag – around 0.1sec, and if you insert 1sec delay between symbols, you won’t need any flow control.

  • Davidb

    I’m having a similar prob – The receiver sometimes saves up all the received bytes and then just releases them in one big lump. The first few are ok though?

    • There are several things to check. First, the packetization timeout – basically, Xbee accumulates some data before sending. It can be configured to zero, if desired. Second is the distance. I saw similar delays when Xbees were far away from each other. Also, I saw it more often when Xbees are working in AT mode; for some reason, API mode is more robust.

  • Davidb

    Hmmm, interesting.
    I have set packetisation to zero for both the co-ordinator and the end device, and the XBees are within 1m of each other! Typing one character per second works, but any faster and occasionally they get buffered and then spurted out, sometimes with one missing… Am just using two computers.

  • Boris

    Добрый день Олег!
    Пишу по русски, чтобы ты не забывал родной язык.
    Я живу в Санкт-Петербурге и работаю в Северо-Западном техническом университете. Сейчас стоит задача разработать аппаратуру для съема физиологических и биомеханических параметров (ЭКС, пневмограмма, электромиограмма, ускорения) со спортсменов во время их тренировок и непрерывной передачи их в реальном времени на ПК тренера. Дальность передачи от 100м до 1-го 2-3 км (разные вариаты), возможно с ретрансляторами.
    Исходя из твоего опыта для модулей Xbee на какую скорость передачи данных можно рассчитывать. И, очевидно, мы можем воспользоваться твоей программой программирования микроконтроллеров. Сейчас у нас наибольшая проблемма – это прогаммирование микроконтроллеров(PIC или TI).
    С уважением, Борис

  • I had same problem with using AT commands to communicate with Xbee’s After first 7~8 bytes (using PC-to-PC terminal software) I would loose any other bytes sent. Then all sudden out no where Id get the lost bytes, this time delay could be seconds to good solid minute! But it only seem happen one direction, forget if it delayed from Cord. to End point or other way around. In any case API mode is way go, really study the Datasheet/Manual, as what I am doing again today! :) Once you “see” how there examples work, and perhaps try pluging them by hand into a terminal program, you will see the Xbee in API mode come alive.

    my two cents anyways…

    Sean-

    • Try to turn flow control on (CTS). Also, PC might simply wait for serial transmit buffer to be filled before sending/receiving the data. Many people report this kind of behavior, however, I’m yet to see one communicating between Xbee series 2 and Linux machine with flow control turned on on both sides.

  • fadh

    I use to have the same problem with my xbee. The connection is the same (with no cts) and I operate in AT mode. The problem is that I set XBEE in multicast mode (DH=0, DL=FFFF for both Xbee). It did sent data between the two but there is delay and as though the data being buffered.

    My solution is to set XBEE in unicast mode ( DH & DL of the first XBEE is the SH & SL of the other XBEE and vice versa). The data came out as expected and there was no delay. For more info on multicast and unicast plz goto http://www.digi.com.

    Hope this will help.

  • andrew

    I get same problem with xbee series 2, coordinator in broadcast mode. Very unreliable transmission. Fine once destination addresses are set.

  • David Crespo

    Hi! I’m now at work with ZigBee modules. I’m trying to communicate a PIC16F84A and a PC with XBee pro but with no results. The problem is that the PIC doesn’t have serial input/outputs. I think that I should use your pic, PIC18F452 in order to achieve an easy connection between PIC and ZigBee. The Pic controlls two motors and I ony wanted to send the commands by Hyperterminal or X-CTU for example.
    I have read your information about PIC-Programming but I don’t understand why should I programm all that in order to implement a transparent connection (replacement of an Serial cable). Could you help me? Thanks Oleg!

  • David Crespo

    Thanks, Oleg. Where could I find information to programm a PIC18F452. I want to test it with a short programm in order to implement PIC–>ZigBee–>PC communication but I have no idea about this PIC, only about PIC16F84A.

  • hugo

    i got the same buffering problem when using 2 xbee as end point (with dh/dl set to coordinator) and a coordinator( with dh and dl set to ffff). does anyone have a solution for this situation ?
    i already tried to set RO to 0 in all of my xbees, and nothing changed.

  • Have you tried to run your serial routines with RTS/CTS flow control?

  • hugo

    yes, it was my last try and i still have this issue. sometimes when sending about 40 bytes packet from coordinator, i have a 2/3 secs receiving delay in end point device. when sending the same 40 bytes packet from end point to coordinator i got no delay. i think it sould be a problem in addressing, because both of end points devices are using coordinator addr as DH and DL, and coordinator is using FF.

    do you think that i can solve this using api mode ?

    thanks,

  • natanel

    Ok I think I solved some xbee problem attaching it to atmel avr32
    what do you think?
    number 3 is relevant but I wrote it all so other may use the implemantaion

    1) there is a problem in atmel mcu using usart and RTS. follow this

    Quote:
    Do not use the hardware handshaking mode of the USART.
    If it is necessary to drive the RTS output high
    when the Peripheral DMA receive buffer becomes full,
    use the normal mode of the USART.
    Configure the Peripheral DMA Controller
    to signal an interrupt when the receive buffer is full.
    In the interrupt handler code,
    write a one to the RTSDIS bit in the USART Control Register (CR).
    This will drive the RTS output high.
    After the next DMA transfer is started and a receive buffer is available,
    write a one to the RTSEN bit in the USART CR so that RTS will be driven low.

    remmber to pdca_disable_interrupt_transfer_complete/pdca_enable_interrupt_transfer_complete as needed.

    2) in XBEE, mcu RTS-> xbee RTS and mcu CTS-> xbee CTS

    3) there is also a problem in XBEE RTS (this was the hard one), after RTS is set there is an over head of 6 byte that will pass (if they where in XBEE RX buffer)
    so add “overhead” byte to each transmition
    in matlab code

    s = serial(port,’BaudRate’,baudrate,’DataBits’,dataBits,’Parity’,parity,’StopBits’,stopbits);
    data=[ 'some data'];
    overhead=[ 0 1 2 3 4 5];

    % open serial
    fopen(s);
    fwrite(s,[ data overhead 1 2 3 4 overhead 5 6 overhead] ,’uint8′);
    fclose(s);

    this will do the trick

    4) as overhead is needed, the MCU RXCHR register will be full
    remmber to empty it before next pdca buffer reloading.
    if not the last overhead byte will be read

    if (usart_test_hit(TEMP_USART))
    junk=(TEMP_USART->rhr & AVR32_USART_RHR_RXCHR_MASK) >> AVR32_USART_RHR_RXCHR_OFFSET;

    5) this is my interupt function

    /*! \USART brief RTS setting
    */
    #if __GNUC__
    __attribute__((naked))
    #elif __ICCAVR32__
    #pragma shadow_registers = full // Naked.
    #endif
    static void pdca_RTS_int_handler( void)
    {
    /* This ISR can cause a context switch, so the first statement must be a
    call to the portENTER_SWITCHING_ISR() macro. This must be BEFORE any
    variable declarations. */
    portENTER_SWITCHING_ISR();

    // prevent re-entering
    pdca_disable_interrupt_transfer_complete( PDCA_CHANNEL_RX);

    // close !(RTS), stop transfer
    TEMP_USART->cr = AVR32_USART_CR_RTSDIS_MASK;

    portEXIT_SWITCHING_ISR();
    #endif
    }

    6) this is my reading code

    // clean last overhead
    if (usart_test_hit(TEMP_USART))
    junk=(ZIGBEE_USART->rhr & AVR32_USART_RHR_RXCHR_MASK) >> AVR32_USART_RHR_RXCHR_OFFSET;
    // load channel
    pdca_reload_channel( PDCA_CHANNEL_RX, (void *) psParametersShadow, sizeof(xParameters));

    // Enable PDCA transfer interrupt when completed
    pdca_enable_interrupt_transfer_complete( PDCA_CHANNEL_RX);

    //set !(RTS), start transfer
    TEMP_USART->cr = AVR32_USART_CR_RTSEN_MASK;

    // wait read end
    while(!(pdca_get_transfer_status(PDCA_CHANNEL_RX) & PDCA_TRANSFER_COMPLETE));

    hope this will help someone

  • guy’s can u help me in preparing code for transmitting some binary sequence

  • Holger

    Hello,
    I’m trying to use the module zigbee UZ2400 of UBEC with pic18f26k20. The is a problem with the communication and no signal is going out. Can you help me with this?
    Thanks in advance
    Holger

    • Your UZ2400 is connected to the PIC via SPI, correct? Have you been able to verify that SPI works correctly without errors – I’ve seen errors on 26k20 when SPI is clocked too fast.

  • Sachitha

    I’m planning to use xbee for a prototype sensor network with 5-6 nodes (with a pic 18F452). I want to be able to program a wireless routing protocol (simplified AODV or DSR) on the PIC to run on xbee. Is this possible?

  • suna

    Hi everyone. V r doin 8th sem proj usin zigbee series 2. V configured one as co ordinator n other as end device. Wit dh dl and sh sl interchanged. Nw how to find out transmission???

  • mat

    Hi, i’m new to xbee and i just want to know if i can connect analog voltages directly to the analog pins of the transmit xbee (without using the USART pins) and expect the voltages to show up in the receive xbee?

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">