Skip to content
M Lange edited this page Apr 8, 2015 · 3 revisions

libmc1322x - Getting Started

libmc1322x is a library, build system, test code, and utilities for the MC13224V from Freescale.

Getting Started

First clone libmc1322x.git:

$ git clone https://github.com/malvira/libmc1322x.git

You need to have sane build environment for the mc13224. If you do not, then get it here.

Otherwise, try building the test programs included in libmc1322x

$ cd libmc1322x/tests
$ make

this will build all the test programs in libmc1322x/tests for each board defined in libmc1322x/board. You should now have programs like:

$ ls *.bin
blink-allio_redbee-dev.bin  blink-red_redbee-dev.bin    nvm-read_redbee-dev.bin   rftest-tx_redbee-dev.bin  tmr-ints_redbee-dev.bin
blink-allio_redbee-r1.bin   blink-red_redbee-r1.bin     nvm-read_redbee-r1.bin    rftest-tx_redbee-r1.bin   tmr-ints_redbee-r1.bin
blink-blue_redbee-dev.bin   blink-white_redbee-dev.bin  nvm-write_redbee-dev.bin  romimg_redbee-dev.bin     tmr_redbee-dev.bin
blink-blue_redbee-r1.bin    blink-white_redbee-r1.bin   nvm-write_redbee-r1.bin   romimg_redbee-r1.bin      tmr_redbee-r1.bin
blink-green_redbee-dev.bin  flasher_redbee-dev.bin      rftest-rx_redbee-dev.bin  sleep_redbee-dev.bin      uart1-loopback_redbee-dev.bin
blink-green_redbee-r1.bin   flasher_redbee-r1.bin       rftest-rx_redbee-r1.bin   sleep_redbee-r1.bin       uart1-loopback_redbee-r1.bin

if you only wanted to build binaries for one board you can do:

$ make BOARD=redbee-dev

The set of boards made is defined in the initial line of libmc1322x/board/Makefile.board:

BOARDS := redbee-dev redbee-r1

edit this line if you want to make a different set of boards.

Loading images to RAM with mc1322x-load.pl

You can load programs on to your mc13224 over UART1 with mc1322x-load.pl in libmc1322x/tools. If you haven't used mc1322x-load.pl before, you will probably need to install a few perl modules first. On Debian/Ubuntu you can install the modules with:

sudo aptitude install -y libdevice-serialport-perl libterm-readkey-perl

To run your code on an Econotag:

$ ../tools/mc1322x-load.pl -f rftest-tx_redbee-econotag.bin -t /dev/ttyUSB1

You must make sure that you are using the correct serial device. With the econotag, for instance, two serial devices show up if you are not using one for openocd. UART1 is usually second device, however. Generally, it's best not to assume that a newly plugged in device will get a particular number.

Flashing images using flasher.bin and mc1322x-load.pl

The following example will flash a program into the NVM storage on the mc13224. Be sure that you are familiar with the erase options for your hardware.

The program libmc1322x/tests/flasher.c works with mc1322x-load.pl to flash an executable image into the NVM memory of the mc13224. mc1322x-load.pl first downloads flasher.bin using the UART1 bootloader and then sends a second file. Now, flasher.bin (which is running on the mc13224), writes this second image to NVM. Then on reset or power up, the mc13224 bootloader will detect this image, copy it to SRAM, and then execute it.

An example of this procedure is shown below:

$ ./mc1322x-load.pl -f flasher_redbee-econotag.bin -s blink-red_redbee-econotag.bin -t /dev/ttyUSB1

<press reset button>

CONNECT
Size: 9552 bytes
Sending flasher.bin
secondary send...
.Detecting internal nvm
nvm_detect returned: 0x00 type is: 0x00000001
nvm_erase returned: 0x00
 type is: 0x00000001
ready
Size: 4820 bytes
Sending blink-red.bin
done sending files.
len: 000012d4
 type is: 0x00000001
nvm_write returned: 0x00
flasher done

<press reset button>

You can also specify additional data to flash from the command line (such as hardware MAC address) as follows:

$ ./mc1322x-load.pl -f flasher.bin -s nvm-read.bin -t /dev/ttyUSB0 0x1e000,0x01020304,0x05060708

<press reset button>

....CONNECT
Size: 9552 bytes
Sending flasher.bin
secondary send...
.Detecting internal nvm
nvm_detect returned: 0x00 type is: 0x00000001
nvm_erase returned: 0x00
 type is: 0x00000001
ready
Size: 8916 bytes
Sending nvm-read.bin
done sending files.
sending 0x1e000,0x01020304,0x05060708,
len: 000022d4
 type is: 0x00000001
nvm_write returned: 0x00
flasher done
writing addr 0001e000 data 01020304
writing addr 0001e004 data 05060708

<press reset button>

Detecting internal nvm
nvm_detect returned: 0x00 type is: 0x00000001
nvm_read returned: 0x00
0x01020304
0x05060708
0xffffffff
0xffffffff

this example programs 0x01020304 and 0x05060708 starting at address 0x1e000.

flashing a 30kB image takes approximately 10 seconds total.

Erasing or invalidating a boot image in NVM

Just as important as flashing and image is erasing an image. There are two good ways to do this:

  • unbrick.bin: if you have JTAG access, the easiest way is to load and exectute unbrick.bin. This is a modified version of nvm-write.c that clobbers the first two bytes of NVM: invalidating any image that resides there.
  • VREF2 toggle: As the mc13224 exits reset, if VREF2H is low and VREF2L is high, this will signal the bootloader to erase the NVM.
    • Redbee Econotag

      • shorting JP15 and JP16. Picture.
      • bit-banging with the FT2232. See the bbmc tool.
    • Redbee Module

      • Flip erase dip switches to erase

Incorporating libmc1322x into your own code

The best way to incorporate libmc1322x into your code is as a git submodule:

$ mkdir newproject
$ cd newproject
$ git init
Initialized empty Git repository in /home/malvira/newproject/.git/
$ git submodule add git://git.devl.org/git/malvira/libmc1322x.git libmc1322x

This will add libmc1322x to your repository. Now to setup the Makefile:

$ cp libmc1322x/tests/Makefile .

You need to edit the Makefile to point MC1322X to your libmc1322x submodule.

change:

MC1322X := ..

to

MC1322X := libmc1322x

or to wherever you've located the submodule

you also need to edit COBJS and TARGETS accordings. COBJS are all of your common code for any of your programs and are rebuilt for each board. TARGETS are the names of your programs.

For instance, say you have a common routine that prints a welcome message and it is used by two programs a and b. You would add common.o to COBJS:

   COBJS:= common.o

and your target line would read:

   TARGETS := a b 

Since COBJS are made for each board, it is ok to have board specific code in there. As an example, tests uses this in tests.c to print the name of the board in your welcome message. You could also use to have different GPIO mappings between boards.

Sending and Receiving packets with the MC13224

Sending and receiving packets with the MC13224 is straightforward using libmc1322x. The maca driver keeps internally a fixed pool of packets. A packet looks as follows:

struct packet {
        uint8_t length; 

        /* offset into data for first byte of the packet payload */
        /* On TX this should be 0 */
        /* On RX this should be 1 since the maca puts the length as the first byte*/

        uint8_t offset;     

        uint8_t data[MAX_PAYLOAD_SIZE+2+1]; /* +2 for FCS; + 1 since maca returns the length as the first byte */
};
typedef struct packet packet_t;

you initialize the radio hardware:

    trim_xtal();

    vreg_init();

    maca_init();

    set_channel(0);  /* 802.15.4 channel 11 */
    set_power(0x12); /* 0x12 is the highest, 4.5dBm */

trim_xtal() trims the on-board crystal to exactly 24 MHz. vreg_init() enables the voltage regulators for the NVM. maca_init() initializes the radio hardware and starts the interrupt driven receive and transmit cycle.

To send a packet in your main code, you request a free packet using get_free_packet(), which returns a pointer the packet (which isn't free anymore, so don't lose it!) or NULL (if there are no free packets available). You then fill the packet however you choose, set the length, set the offset to 0, and call tx_packet() and pass it the pointer to the packet you want transmitted. tx_packet() inserts the packet into the driver's transmit queue and the radio will transmit it as soon as possible.

  p = get_free_packet();
  
  if(p) {
        fill_packet(p);
        tx_packet(p);
  } else {
        printf("can't get free packet\n");
  }

packets are received automatically and stored in the receive queue. rx_head is the head of the queue and is non-zero if there is a packet waiting. You can test for this if you'd like. To receive the packet you call rx_packet(), which returns a pointer to the packet or NULL. Like before, the returned packet is removed from the receive queue --- it is not free yet. You can then do what you like to the packet. The payload starts at p->offset and is p->length long. When you are done, free the packet with free_packet():

if((p = rx_packet())) {
    /* print and free the packet */
    print_packet(p);
    free_packet(p);
}

That's it! Now go do lots of wireless things!

This page is maintained by Mariano Alvira. Please email me at mar@devl.org with patches, suggestions and comments.