« 11 inch MacBook Air and MATLAB | Main | 11 inch MacBook Air and Autocad »
Saturday
Nov132010

XBee & Propeller Chip

Introduction

When working with embedded electronics, microcontroller based systems in particular, it’s often necessary to monitor their state remotely. Microcontrollers can be difficult to debug and monitor because they are basically computers without peripherals. Although it’s possible to permanently attach a display and input device to a microcontroller, it’s usually impractical, as they are often embedded in hard to reach dynamic systems. In cases where it is necessary to have the ability to monitor or reconfigure microcontroller based systems, doing so through a wireless link can greatly simplify the process. In the case of mobile objects, like robots or unmanned-vehicles, a wireless link might be the only option.

There are several ways a wireless link be established between two systems. In this example, we’ll be establishing a link between a microcontroller on the remote end, and monitoring the data it sends on a local computer. Although almost any combination of microcontroller and computer could be used, this example will use a Propeller Chip, an eight core microcontroller made my Parallax, and an Apple laptop computer.

For a wireless link, we’ll use an XBee 900 module from Digi International. XBee modules are a good choice for small systems, because they are relatively cheap, and interchangeable. If for some reason you decide to replace a 900 MHz module with a 2.4 GHz module, minimal re-configurations are needed. The reason for using a 900 MHz module in this example as apposed to a marginally faster 2.4 GHz unit is because of the superior range that comes with using 900 MHz.

XBee modules can be operated in two different modes: transparent and API. Transparent mode is very convenient since the modules require no configuration; every byte pushed into one module exits the other as though there’s a serial cable connecting them. Despite the convenience of using transparent mode, we’ll be using API mode. It’s a bit more difficult to implement, but the benefits outweigh the added complexity. API mode allows greater control of the link, with the ability to send packets to an explicit address. In contrast, when data in sent in transparent mode, it is sent to all modules within range.

Protocol

In transparent mode, transmission of a byte only requires it to be sent to the local XBee. After a certain timeout period, that XBee module packetizes any bytes in its buffer and sends them to the remote XBee(s), which output the bytes to whatever hardware is attached to them. API mode is a bit different. Much of the data formatting that is done automatically by the XBee in transparent mode needs to be performed before the user can transmit. For instance, the procedure to transmit the byte value 0x7E in transparent may look like this (in pseudo code):

serialTransmit(0x7E)

Sending data in API mode is not so simple. Before further discussion, it must be noted that API mode has two sub-modes: escaped and unescaped. Escaped mode requires that any data that can conflict with API control-characters must be preceded by 0x7D and XOR’d with 0x20. That procedure ensures that the XBee module won’t be confused with any user data that happens to be same as any of the XBee control characters. This example will use escaped mode. It has the added benefit of making it easier to program receive routines.

Let’s revisit our earlier example of sending the byte 0x7E. All that was required to send a byte was a single function call. In API mode several packet formatting steps must first take place:

  1. Create a temporary buffer guaranteed to be bigger than needed
  2. Insert 0x7E into position 0, this is the XBee frame delimiter, indicating the start of a new API packet.
    0
    0x7E
  3. Calculate the length of the packet, which in our case will be several bytes longer than the single 0x7E we want to send. Put the upper 8 bits of that length into buffer position 1, and the lower 8 bits into position 2.
    1 2
    0x00 0x0F
  4. Add the XBee API identifier to position 3. There are several ID’s for different purposes, but we are trying to send a packet to another XBee, so we will use 0x10, which is the TX Request id.
    3
    0x10
  5. Insert a unique frame ID byte into position 4. This is not very important unless you want the module to respond with an acknowledge packet that it received the transmit request. However, a byte needs to be here, so we’ll use 0x01.
    4
    0x01
  6. Insert the 64 bit address of the remote module into positions 5-12, send the most significant byte first. Let’s assume the remote XBee’s address is 0x13A200404B2277.
    5 6 7 8 9 10 11 12
    0x00 0x13 0xA2 0x00 0x40 0x4B 0x22 0x77
  7. Insert the 16 bit address of the network you are operating on into positions 13-14, MSB first. We’ll use the address 0xFFFE, since it is the default.
    13 14
    0xFF 0xFE
  8. Insert 0x00 into both position 15 and 16. These fields have definitions, but are not flexible and serve no real purpose.
    15 16
    0x00 0x00
  9. Finally, starting at position 17, insert however many bytes you need to send. In our case, just insert 0x7E into position 17.
    17
    0x7E
  10. Calculate the checksum of the packet and insert it into position n, which in our case is 18. To calculate checksum, we add all the bytes from positions 3 to n-1, discarding any carry and keeping only the bottom 8 bits. Subtract this number from 0xFF. What is left over is our checksum. Checksum = 0xFF - ((0x00 + 0x01 + 0x00 + 0x13 + 0xA2 + 0x00 + 0x40 + 0x4B + 0x22 + 0x77 + 0xFF + 0xFE + 0x00 + 0x00 + 0x7E) & 0xFF)
    Checksum = 0xAA
  11. Our (almost) completed packet looks like:
    0 1 2 3 4 5 6 7 8 9
    0x7E 0x00 0x0F 0x10 0x01 0x00 0x13 0xA2 0x00 0x40
    10 11 12 13 14 15 16 17 18
    0x4B 0x22 0x77 0xFF 0xFE 0x00 0x00 0x7E 0xAA
  12. Starting at byte 1, we must enumerate through the whole packet and escape any control characters. Any byte with the value 0x7E, 0x7D, 0x11, 0x13 must be replaced with 0x7D, and be followed by that byte’s value XOR’d with 0x20. Since our packet has a 0x13 at index 6, and a 0x7E at index 17, we will have to do two escapes. After escaping those two bytes, our packet will look like this:
    0 1 2 3 4 5 6 7
    0x7E 0x00 0x0F 0x10 0x01 0x00 0x7D 0x33
    8 9 10 11 12 13 14
    0xA2 0x00 0x40 0x4B 0x22 0x77 0xFF
    15 16 17 18 19 20
    0xFE 0x00 0x00 0x7D 0x5E 0xAA
  13. Lastly, all that is left in order to send the packet is to transmit bytes to the XBee module over the serial line.

Implementation

Since a link is no good unless there is something on both ends to process the data it carries, we’ll have to implement the XBee packet processing on both the remote and local ends. In this case, the remote end is a Propeller Chip, and the local end is an Apple MacBook computer. Since they both use different programming languages, and have different functionality, we’ll have to create send an receive functionality twice. The Propeller Chip is a 32-bit 8 core microcontroller, has no operating system, and is programmed in a quasi object-orientated language called Spin. The MacBook is programmed with the NeXTstep API, which was acquired by Apple Computer and renamed Cocoa. Cocoa is programmed in Objectective-C, and plain ANSI C.

Propeller Chip

Because the Propeller Chip is multi-cored, it is actually quite easy to implement XBee send and receive functionality.

Receive Function

PUB receivePacket(_escaped) | char, index, length, checksum
  'clear lenght and checksum to 0
  length~     
  checksum~
  'receive bytes until we get a 0x7E
  repeat until (char := uarts.rx(port)) == $7E      
  'get a byte, escape it if needed, and make it the first length
  'word by shifting it 8 bits to the left
  char := uarts.rxtime(port, 1)
  if char == $7D AND _escaped 
    length |= (uarts.rx(port) ^ $20) << 8
  else
    length |= char << 8
  'do the same, but don't shift this time, since the next byte
  'is the lowsest signifigant byte of the length word
  char := uarts.rxtime(port, 1)
  if char == $7D AND _escaped
    length |= (uarts.rx(port) ^ $20)
  else
    length |= char
  'clear index to 0
  index~
  'repeat length times
  repeat while index < length + 1
    char := uarts.rx(port)
    'need to un-escape it
    '0x7D indicates that the next byte is the actual byte
    'we ignore the 0x7D and use the next byte
    if char == $7D 
      'XOR the char with 0x20
      receiveBuffer[index] := uarts.rx(port) ^ $20
    'not an escaped byte, take it as is
    else
      receiveBuffer[index] := char
    'calculate checksun with every iteration of the loop
    'advance the index variable by 1
    checksum += receiveBuffer[index++]
  'AND checksum with 0xFF do keep only the lower 8 bits
  checksum &= $FF
  'if we have a valid packet, all the bytes after lenght, including
  'the last byte, checksum, added together equal 0xFF
  if checksum <> $FF
    'checksum didn't check out, return -1 to the caller
    return -1
  'so far, this receive method only accounts for packets
  'sent from other XBee modules, not acknowlege packets
  'or various status packets 
  case receiveBuffer[0]
    'if the first byte after length is 0x90, we are dealing
    'with received packet from another XBee module
    'subtract 12 from length, since the user is only concerned with
    'the length of the meaningful data in the packet, not addresses
    'and such, since they are static, and always the same length
    $90:  rxLength := length-12
          'shift then AND bytes 1..4 to get the upper 32 bit address
          'of the sending module
          rxRemoteAddressUpper32 := receiveBuffer[1] << 24 
                                    | receiveBuffer[2] << 16 
                                    | receiveBuffer[3] << 8 
                                    | receiveBuffer[4]
          'shift then AND bytes 5..8 to get the lower 32 bit address
          'of the sending module
          rxRemoteAddressLower32 := receiveBuffer[5] << 24 
                                    | receiveBuffer[6] << 16 
                                    | receiveBuffer[7] << 8 
                                    | receiveBuffer[8]
          'shift then AND bytes 10..11 to get the 16 bit network address
          rxNetworkAddress16 := receiveBuffer[10] << 8 
                                | receiveBuffer[11]
          'move the important data from receiveBuffer[] to rxData[]
          'so the caller can access it
          bytemove(@rxData, @receiveBuffer[12], rxLength)
          'return 0x90 to the caller, so it knows an rx packet was
          'received
          return $90

Send Function

 pub apiArray(_64BitDestinationAddressUpper, _64BitDestinationAddressLower, _16BitNetworkAddress, _arrayAddress, _arraySize, _escaped)| Length, chars, checkSum,ptr,sourceArrayPtr
      'clear the index
      ptr := 0        
      'add 0x7E to byte 0 of array
      dataSet[ptr++] := $7E       
      '_arraySize is set by caller, we have to add 14 to it
      'to account for the added bytes API mode requires
      Length := 14 + _arraySize        
      'add MSB of length to array
      'add LSB of length to array                     
      dataSet[ptr++] := Length >> 8                         
      dataSet[ptr++] := Length
      'add 0x10 to indicade a TX request API packet                              
      dataSet[ptr++] := $10
      'add frame id, value passed in but isn't important                                 
      dataSet[ptr++] := _FrameID    
      'the remote 64 bit address is passed by caller
      'in two longs, we need to split up those 2 longs
      'into 8 bytes and add them to the array
      dataSet[ptr++] := _64BitDestinationAddressUpper >>24  
      dataSet[ptr++] := _64BitDestinationAddressUpper >>16  
      dataSet[ptr++] := _64BitDestinationAddressUpper >>8   
      dataSet[ptr++] := _64BitDestinationAddressUpper       
      dataSet[ptr++] := _64BitDestinationAddressLower >>24  
      dataSet[ptr++] := _64BitDestinationAddressLower >>16  
      dataSet[ptr++] := _64BitDestinationAddressLower >>8   
      dataSet[ptr++] := _64BitDestinationAddressLower 
      'the 16 bit network address is passed by caller
      'as a word, we need to split it into 2 bytes      
      dataSet[ptr++] := _16BitNetworkAddress          >>8   
      dataSet[ptr++] := _16BitNetworkAddress      
      'unimportant, but the XBee expects these two bytes         
      dataSet[ptr++] := $00                                
      dataSet[ptr++] := $00
      'the caller passed us the address to a byte array
      'that is in HUB memory, the caller also passed
      'in _arraySize, so we know how many bytes from that
      'array to read. Jut loop until we have read all the
      'bytes and written them into our array                                 
      repeat sourceArrayPtr from 0 to _arraySize - 1       
        dataSet[ptr++] := byte[_arrayAddress++]      
      'start with checksum equals 0xFF, then we subtract all
      'the bytes we encounter in our outgoing packet until
      'we reach the end       
      checkSum := $FF                                       
      Repeat chars from 3 to ptr-1                          
        checkSum := checkSum - dataSet[chars]
      'add our calculated checksum to the end off the array
      dataSet[ptr] := checkSum
      'if in escaped mode, loop through our outgoing
      'array and escape any characters as necessary
      'send them on the fly to the XBEee module
      'there's no need to store them in memory first
      if (_escaped)
        tx(dataSet[0])
        Repeat chars from 1 to ptr
          if (dataSet[chars] == $7E OR 
              dataSet[chars] == $7D OR 
              dataSet[chars] == $11 or 
              dataSet[chars] == $13)
            tx($7D)
            tx(dataSet[chars] ^ $20)
          else
            tx(dataSet[chars])
      'if not escaped mode, send the bytes as they are
      else
        Repeat chars from 0 to ptr
          tx(dataSet[chars])

Computer

Due to the nature of event driven Objective-c, the computer code is a bit fragmented and spans many more lines and several files. It’s a bit out of scope to include in this post, but source is available for download.

Downloads

Cocoa Code

Propeller Code

PrintView Printer Friendly Version

EmailEmail Article to Friend

References (59)

References allow you to track sources for this article, as well as articles that were written in response to this article.
  • Response
    Just wanna commentabout this article, after reading whole of this it make me to have new thinking about one important event, hope I can read more good news again from you so I bookmark your website.
  • Response
    Response: tYRtMEIn
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Response: lgxDYmJd
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Response: rmbs.ca
    I added your site to Favorits. I am constantly monitored. All of your posts very interesting.
  • Response
    Thanks for the info. This is primarily what I was looking for. I am currently researching this topic so I will be back. Can you tell me how to subscribe to your blog?
  • Response
    Response: farquharson.co.za
    Well, the post is in reality the best on this notable topic. I fit in with your conclusions and will thirstily look forward to your next updates. Just saying thanks will not just be sufficient, for the great clarity in your writing. I will right away grab your rss feed to ...
  • Response
    Response: inteltronics.co.za
    With all the doggone snow we have had lately I am stuck indoors, fortunately there is the internet, thanks for giving me something to do.
  • Response
    Loveland accountants
  • Response
    Response: originalwin7
    I cant agree more with what you wrote you and I appreciate the exact same thinghs as you ! Please compose far more and I bookmarked you !
  • Response
    Response: www.turbarn.no
    thats one way to handle your money, but that sounds a bit like a "2 wrongs make a right" plan of action. While tempting, I think I will stick to trying to control my spending and putting aside what I can for a rainy day. For me, it is often a ...
  • Response
    Get Naughty internet marketers
  • Response
    Response: Check This Out
    Amazing Site, Carry on the beneficial job. Thanks for your time!
  • Response
    Response: alle Xovilichter
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Response: organic hair color
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Response: Hemroid relief
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Response: plumbers in Rogers
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Response: 128gb micro sd
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Response: surprise eggs
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Response: best shower head
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
  • Response
    But at this mo ralph lauren skjorte ment. The more troublesome thing ha ralph lauren polo dame ppened. The six general headquarters in star magic openly defected. Think about it, but the existence of the six small universe. So, the star headquarters soon fell into the h Dame Pony Polo ands ...
  • Response
    」楚天聖陰険な笑いが、瞬間と龙鹰合体、いつ何時戦いの準備.潸潸さっと潸潸!5人は落ちて、彼らの光が上半身を持って六角陣盤、形成五角の勢いを楚天聖四人に囲ま Specialized Jersey Sale れ、一言言わず手を打ち出し、陣の束光の柱を直接閉鎖空間、禁固空気中の偽星の力、うつ楚天聖らない措置の手.光を楚天聖の4つのあの5人と Specialized Jersey Sale ともに消え、が妍の体が現れる小峰に、器の霊が竜魂で力を凝聚して出*、駅の峰の上で、瀋黙の後で、高い人,Specialized Jersey Sale.七星聖母先着古星大陸でも古家先古星まで大陆の.妍を占めてずっと Specialized Jersey Sale わ
  • Response
    "Hum!" Cold hum ring. The crush Sky Jersey ed blood fog surging,Sky Jersey, quickly gathered together. A Sky Jersey ndy reorganization, sneer at to looking at Jiang Xiaofan: "their forces are converging in the king, the ultimate holy operation support, Sky Jersey the king now is real
  • Response
    Response: GoPro Pole
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Most people do not know this is Specialized Jersey how to return a responsibility, but the two father is very clear, t Specialized Jersey Sale he Land Bureau plainly behind is Yuwen home, this time all of a sudden want to start to Zijin villa, the likelihood is want revenge. Pang ...
  • Response
    Response: Sky Jersey
    "Li Hao, this is not your lotus seat!" In the distance, a 'black hole' Sky Jersey show, Zhang Ming from Sky Jersey out of tow, twelve Black Lotus, with his smiling face. "Donor, butcher, repent and be saved!" On the other side, a statue of Buddha stepped forward and, at Sky ...
  • Response
    Response: Sky Jersey 2012
    “是啊,我们现在所拥有的一切, Sky Jersey 都是长辈们中下的种子,我们能做的,便是长得高大,长得健硕,将他们的意志更加完美的传承下去!”灵儿笑容满面望着李昊,有种发 Sky Jersey 自内心的欣喜。。 “你还真是不愧是个妖精,言语中总有着让人着迷的魅力,Sky Jersey!”李昊歪着头,笑嘻嘻的看着灵儿说道。被一语点醒,李昊只觉得浑身清爽无比,笼罩在心头的阴霾被驱散,让他有了重生般的感觉,宛如升华般透彻。再次看向灵儿,也不禁感觉更是亲近。 听着他的调笑,灵儿不由皱了皱鼻,小嘴微启,露出两颗放光的小虎牙,笑 Sky Jersey 眯
  • Response
    Response: Adidas Sky Jersey
    你们还得感谢,Sky Jersey,感激我,膜拜我!但我倒要看看,你们这些道貌岸然的伪君子。被揭穿了真面目之后,今后又如何在这 Sky Jersey 人世间立足! 一君莫邪恶狠狠地如是想到。 “赎清罪孽吗?”梅高节浑浊的目光一亮,就像抓住 Sky Jersey 了一根救命的稻草:“我这样的莫大罪孽,真的可以赎得清吗?” “不能,有些罪孽是没得挽回的,但却仍能就那些可以挽回的罪孽做出补救,我相信大人可以尽自己之能减少那些还可挽回的罪孽”。君莫邪就像一个正在诱惑小红帽的老巫婆。循循善诱的道。 “哈哈”君莫 Sky Jersey 邪
  • Response
    She's really not greedy, just for a while! Li Shaoyang doesn't know whe Hatte Polo re Lucy is sad,Hatte Polo, but in the kitchen with his Ralph Lauren Dame Pony Polo favorite vegetables and lean meat porridge. The mouth is still humming a song. When Li Shaoyang cook,Ralph Lauren Dame Pony ...
  • Response
    私は……私は彼らを傷つけ,Dame Classic Dame Classic Fit Pony Polo Fit Pony Polo.聞いていて笑っておいたら、苦痛.当初提案市内へ行き訓練場を打って殺人の人は彼の場合は、彼はそそく Ralph Lauren Hatte さと助言し、彼らも落ちないアンドリューあれらの人の手に.よかった、あなたも悲しまないで、彼らが生きている限り、すべて問題ではない.特魯て胸いっぱい後ろめたいナイスに無力.ナイスがこのアイディアも彼のために.もし彼がすべて深い恨みを置いて、もし当初そのケンは彼らを見つけたとき、彼は断固としてはねと協力し、彼らもこのダメージ Dame Pony Polo を
  • Response
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    !!夫!!!二つの Sky Jersey 美しい靓影、例えば鳩のひな投怀撲入古峰ように抱かれ、しっかり彼を抱いて、黒目 Sky Jersey がちな目の中で、水のようなやさしいばかり,Sky Jersey.…………数年後に.荒野の大陸、古林獄海、霧の峡穀、七色池塘边.ここの美しいは、それ自体をされて古峰に行った素石鉱脈ない色のところで、今も再び煥を美しい七色光景.ざらざら!水の音が聞こえ、七色の池の中で、二人の美しい麗人は水中に追いかけっこに遊び、飛沫が散る、真っ白に半露、春には.「こ Sky Jersey っこっこ……雨荷お姉さん、あなたはその旦那さんに任せて……
  • Response
    Response: BB8 Toy
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Response: sneak a peek here
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Response: Insert your data
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Response: GoPro Attachments
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Response: GoPro Accessories
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Response: insert your Data
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Response: aiheconf.ir
    Chasing 'trons - Main - XBee & Propeller Chip
  • Response
    Response: Insert your data
    Chasing
  • Response
    Response: Insert Your Data
    Chasing
  • Response
    Response: Media
    I found a great...
  • Response
    Response: insert your data
    Chasing

Reader Comments (2)

Thanks, it helped.

December 20, 2011 | Unregistered CommenterM11

HI there Jay,

Great tutorial, in fact the best one I've read so far.

I do have a question

I have used a coordinator connected to the PC and router connected to PIC Microcontroller with an LCD to visualise the data, in two setups:

1- Coordinator in API MODE and Router in AT mode, every thing works fine I could send the API packet from Coordinator and receive it on the LCD in the router node.
2- Both Coordinator & router in API mode, when sending a char from the coordinator I receive random char on the LCD in the router end.

My qst is do I need a special algorithm to interpret the data received in the router?

November 15, 2012 | Unregistered Commenternoak

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Post:
 
Some HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>