ZigBee модуль Microchip-MRF24J40MA

Встала необходимость осваивать радиоканал. Стояла задача — передача небольших объемов информации с большого количества устройств. Начал рассматривать варианты.

  • Блютус (на него изначально упал взгляд у заказчика). Не подошел — малое расстояние, и не более 7 устройств в сети.
  • Вай-фай. Не более 32 устройств в сети. Не подошел.
  • Разнообразные трансиверы — удлинители ком-порта. В основном предназначены для работы в режиме точка-точка.
  • ZigBee-образные устройства. Стандарт IEEE-802.15.4. Приглянулись сразу. Вот про них и рассказ.

Для целей ознакомления остановился на готовом модуле от Microchip – MRF24J40MA. На алиэкспрессе продается, тут. У атмелов есть похожий чип AT86RF220 и интегрированное решение ATMEGA128RFA1. Облизнулся на последний, но в пределах досягаемости не было, под заказ — долго. Но обязательно потом возьму, погоняю.

Знакомство
Итак, встречайте героя. Модуль MRF24J40MA на чипе MRF24J40.

MRF24J40MA


На платке размером 18х28 мм находятся: антенна, собственно чип, кварц на 20 Мгц, ВЧ-обвязка (конденсаторы и дроссели) и буфер выхода. Буфер стоит из-за ошибки: чип не переводит выход в высокоомное состояние при неактивности. Связь с хост-контроллером — по SPI, плюс отдельные пины на прерывание и пробуждение.
Работа ведется на частоте 2.4 Ггц (каналы 11-26).
Потребляет 18-22мА.

Ссылка на страничку оф.сайта: Microchip
Там есть ссылки на даташиты и примеры программ.

Вот схема связи с контроллером:

Есть два режима работы беспроводной сети — с использованием координатора, и без него. В режиме с координатором одно устройство конфигурируется как координатор: оно занимается синхронизацией сети, раздачей тайм-слотов, рассылкой служебной информации, организация взаимодействия между подсетями. При этом достигается наименьшее энергопотребление — устройство большую часть времени спит, активируется в свой тайм-слот.
В режиме работы без координатора приемники каждого устройства включены постоянно.

Какие еще вкусности умеет трансивер:

  • имеет на борту буферы под один пакет на отправку и один пакет на прием (длина пакета — до 128 байт вместе со служебной информацией);
  • автоматически определяет и разруливает коллизии (CSMA-CA);
  • формирует и проверяет CRC-16;
  • автоматически отсылает подтверждение о приеме пакета (если требуется), также перепосылает пакет, если не пришло подтверждение;
  • анализирует заголовок пакета, фильтрует по адресу получателя. Может работать и в promiscuous mode (прослушивать канал);
  • замер RSSI;
  • встроенное шифрование пакетов (AES-128).

Адресация устройств может происходить как по короткому (16 бит), так и по длинному (64 бит) идентификатору.

Подключаем.
На макетке подключил выводы SPI (MISO, MOSI, SCK, CS), Reset, Int. Wake не подключал.
Подал питание 5 В. Несмотря на то, что в спецификации чипа указано 3.6 В максимум, все заработало и так. Хотя может мне чипы живучие попались. Когда заметил, снизил напряжение питания всей макетки.

Коммуникации.
Для того, чтобы прочитать (или записать) один байт из внутренней памяти чипа, необходимо затратить 24 такта SPI. При частоте МК 8 Мгц, делителе частоты SPI = 4, получается скорость передачи (и приема) не более 8 Кб в секунду. То есть это скорость работы с буферами. Скорость передачи пакетов, естественно, выше. В описании протокола ZigBee: The 2.4 GHz band provides up to 250 kbps. Мне пока хватает.

По адресации память трансивера разделена на две области: доступ по короткому адресу (6 бит) и доступ по длинному адресу (10 бит). На картинке показан доступ по длинному адресу.
В области коротких адресов (0х00-0х3f) находятся почти все регистры управления. В области длинных — буфера и еще десяток регистров.

Вот процедуры общения с памятью трансивера:

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
29
30
31
32
33
34
35
36
37
// запись по короткому адресу
void MRF_write_s(uint8_t addr, uint8_t data){
	SPI_PORT &= ~_BV(SPI_P_SS);
	SPI_master_write(((addr<<1) & 0x7f) | 0x01);
	SPI_master_write(data);
	SPI_PORT |= _BV(SPI_P_SS);
}
 
// чтение по короткому адресу
uint8_t MRF_read_s(uint8_t addr){
	uint8_t data;
	SPI_PORT &= ~_BV(SPI_P_SS);
	SPI_master_write(((addr<<1) & 0x7e));
	data = SPI_master_write(0);
	SPI_PORT |= _BV(SPI_P_SS);
	return data;
}
 
// запись по длинному адресу
void MRF_write_l(uint16_t addr, uint8_t data){
	SPI_PORT &= ~_BV(SPI_P_SS);
	SPI_master_write(((addr>>3) & 0x7f) | 0x80);
	SPI_master_write(((addr<<5) & 0xe0) | 0x1f);
	SPI_master_write(data);
	SPI_PORT |= _BV(SPI_P_SS);
}
 
// чтение по длинному адресу
uint8_t MRF_read_l(uint16_t addr){
	uint8_t data;
	SPI_PORT &= ~_BV(SPI_P_SS);
	SPI_master_write(((addr>>3) & 0x7f) | 0x80);
	SPI_master_write(((addr<<5) & 0xe0));
	data = SPI_master_write(0);
	SPI_PORT |= _BV(SPI_P_SS);
	return data;
}

Все согласно даташита. Адреса регистров тоже оттуда.

Бег по граблям.
Скурив даташит, нашел в нем пример инициализации. Правда для ПИКов, но это меня не остановило. Посмотрел, в какие регистры какое значение записывается, записал, выждал. На выходе — болт. Скачал с сайта Микрочипа софт для работы с этим модулем, там в составе была готовая прошивка ПИКа. Почитал и удивился — дополнительно инициализировались регистры, которые не были описаны в даташите. Естественно, какими-то волшебными значениями.
Переписал процедуру инициализации. Ура! Первый пакет отправлен.

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// инициализация
void MRF_init() {
	uint8_t i;
 
	SPI_master_init();
 
	// Hard reset
	MRF_DDR_RESET |= MRF_P_RESET;
	MRF_PORT_RESET &= ~MRF_P_RESET;
	_delay_ms(100);
	MRF_PORT_RESET |= MRF_P_RESET;
	_delay_ms(100);
 
	// Программный сброс трансивера.
	MRF_write_s(MRF_SOFTRST, 0x07);
    while (MRF_read_s(MRF_SOFTRST) & 0x07);
 
    //PACON2 = 0x98, Initialize FFOEN=1 and TXONTS = 0x6
    MRF_write_s(MRF_PACON2, 0x98);
    //Initialize RFSTBL = 0x9
    MRF_write_s(MRF_TXSTBL,0x95);
    //Initialize VCOOPT=1
    MRF_write_l(MRF_RFCTRL1, 0x01);
    //Enable PLL
    MRF_write_l(MRF_RFCTRL2, 0x80);
    //Initialize TXFIL=1, 20MRECVR=1
    MRF_write_l(MRF_RFCTRL6, 0x90);
    //Initialize SLPCLKSEL = 0x2 (100KHz internal oscialltor)
    MRF_write_l(MRF_RFCTRL7, 0x80);
    //Initialize RFVCO =1
    MRF_write_l(MRF_RFCTRL8, 0x10);
    //Initialize CLKOUTEN=1 and SLPCLKDIV = 0x01
    MRF_write_l(MRF_CLKCTRL, 0x21);
    //Set CCA mode to ED
    MRF_write_s(MRF_BBREG2, 0x80);
    //Set CCA-ED Threshold
    MRF_write_s(MRF_RSSITHCCA, 0x60);
    //Set appended RSSI value to RX FIFO
    MRF_write_s(MRF_BBREG6, 0x40);
    //INTCON (0x32) = 0xF6 - Enables only TXNIF and RXIF interrupts
    MRF_write_s(MRF_INTMSK, 0xF6);
    //set operating channel as channel 11
    MRF_setChannel(CHANNEL_11);
    _delay_ms(100);
    //Wait until the RFSTATE machine indicates RX state
    while((MRF_read_l(MRF_RFSTATE) & 0xa0) != 0xa0);
    // Program the short MAC Address, 0xffff
    //load the short address of the device with 0xffff which means that it will be ignored upon receipt
    MRF_write_s(MRF_SADRL, 0x12);
    MRF_write_s(MRF_SADRH, 0x34);
    //load the pan address also with 0xffff;
    MRF_write_s(MRF_PANIDL, 0xff);
    MRF_write_s(MRF_PANIDH, 0xff);
 
    //Program Long MAC Address
    for(i=0;i<8;i++)
    {
        MRF_write_s(MRF_EADR0+i,0x11);
    }
 
    // Automatic acknowledgement is not transmitted for received packets by TXMAC
    //ERRpkt mode bit is set to 0
    //Promiscuous packet mode bit is set to 1
    MRF_write_s(MRF_RXMCR, 0x21);
}

Процедура отправки пакета примитивна — заполняем буфер, даем команду на отправку. То же самое и при приеме — получив прерывание от устройства, считываем буфер приема и разбираем, что же мы получили. Проверки на CRC и на соответствие адреса получателя лежат на плечах чипа, МК получает уже рафинированные данные, что не может не радовать.

Пример отправки пакета:

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
MRF_write_l(0x000, 22); // packet header length //
MRF_write_l(0x001, 23); // total packet length (not including the FCS/CRC or length) //
MRF_write_l(0x002, 0b01100001); /* last byte of packet (the LSB of the frame control p112 of IEEE 802.15.4-2003) -- Data packet, no security, no frame pending, ACK requested, intra-pan transmission */ 
MRF_write_l(0x003, 0xCC); /* first byte of packet (the MSB of the frame control p112 of IEEE 802.15.4-2003), use long addresses for both cases */     
MRF_write_l(0x004, 0x01); // IEEE sequence number //
MRF_write_l(0x005, 0xFF); // PANID - broadcast //
MRF_write_l(0x006, 0xFF); // PANID - broadcast //
MRF_write_l(0x007, 0x01); // Dest Address LSB //
MRF_write_l(0x008, 0x23); // Dest Address  //
MRF_write_l(0x009, 0x45); // Dest Address  //
MRF_write_l(0x00a, 0x67); // Dest Address  //
MRF_write_l(0x00b, 0x89); // Dest Address  //
MRF_write_l(0x00c, 0xab); // Dest Address  //
MRF_write_l(0x00d, 0xcd); // Dest Address  //
MRF_write_l(0x00e, 0xef); // Dest Address MSB //
MRF_write_l(0x00f, 0x11); // Source Address LSB //
MRF_write_l(0x010, 0x11); // Source Address  //
MRF_write_l(0x011, 0x11); // Source Address  //
MRF_write_l(0x012, 0x11); // Source Address  //
MRF_write_l(0x013, 0x11); // Source Address  //
MRF_write_l(0x014, 0x11); // Source Address  //
MRF_write_l(0x015, 0x11); // Source Address  //
MRF_write_l(0x016, 0x11); // Source Address MSB //
MRF_write_l(0x017, 0x55); // data byte //
MRF_write_l(0x018, 0xAA); // data byte //
 
MRF_write_s(MRF_TXNMTRIG, 0x01);  //force transmit

Структура пакета приведена в даташите, как я уже говорил, можно адресовать устройства по 16-битовому адресу или по 64-битовому. В данном пакете используются 64-битные адреса.
Максимальная длина пакета (с заголовком) — 127 байт.

После приема пакета в буфере есть бонус — байт качества линка и силы сигнала для данного пакета. То есть сразу можно отслеживать и отображать качество линка, при необходимости принимать меры.

На дальность особо не проверял, но из комнаты в кухню через две бетонные стены принимает уверенно.

Цена вопроса
Около 300рублей за модуль.

Сырки
MRF24J40.c
MRF24J40.h

66 thoughts on “ZigBee модуль Microchip-MRF24J40MA”

      1. угу. точно 404: _http://www.elitan.ru/price/index.php?seenform=y&find=MRF24J40MA&flag=everywhere&mfg=all
        + у них еще и самовывоз платный (500р).

        Нижненовгородские магазины тоже не подходят, т.к. доставка нивелирует всю прелесть низкой цены ((

    1. Декларируют 100м на прямой видимости. Еще не проверял.

      Зато без проблем организовывать сеть типа «умный дом». Для него, собственно, ZigBee и разрабатывался.

      1. А из чего бы подальше «стрелить»? Тут стоит задача передавать в движении из одного автомобиля в другой расстояние (чтобы между ними расстояние ПО ДОРОГЕ постоянно в движении вычислять). Расстояние, выдерживаемое между автомобилями во время движения, должно быть порядка 350 метров, так что с запасом бы модульки где-то на километр. И чтобы не слишком дорогие. В идеале вообще бы к «уоки-токи» подцепиться или тональные модемы к ним приделать. Но это нагроможение какое-то получается, если бы были подходящие модули, большое бы облегчение вышло :). Процессоры в приборах, измеряющих расстояние в обоих автомобилях, имеются, еще бы к ним радиомодули «дальнобойные» подключить…

  1. Не разобрался с фразой «устройство большую часть времени спит, активируется в свой тайм-слот.» Погуглил слово тайм-слот, передача получается связана с временным разделеним каналов. Если у каждого устройства есть своё и только своё время вещания, значит не может быть коллизий. Или я скорее какие-то понятия перепутал.

    1. Как я уже писал, есть два режима работы сети — топология «звезда» и peer-to-peer. При работе звездой всегда выделяется центральное устройство. Оно регистрирует всех видимых и расписывает им периоды, когда можно общаться, а когда нельзя и рассылает пакеты синхронизации («beacons»). В этом режиме вся нагрузка возложена на центральное устройство. Большинство коллизий исключены, так как каждое устройство общается только в выделенное время.
      Но тем не менее, всегда на канал может выскочить другое подобное устройство, не настроенное на работу с центром, например. В этом случае возникнет коллизия — два передатчика будут вещать на одной частоте. Поэтому механизм коллизий включен всегда.

    1. Смотри по тегу «радиопередача» — хопрф модули на этих штуках и сделаны.
      У MRF49XA куча полных аналогов от различных производителей, народ прилично использует в своих проектах, достаточно лишь загуглить. Только вот гемора там всякого много по части радиопередачи и соединения с мк. Здесь же получаешь простой интерфейс с гарантированной безошибочной доставкой. Но дорого.

    1. Но по тем ссылкам ведь только комповый конец USB/блютус. А где второй брать, с выходом блютус/RS232? Там — то их вроде нету. А то, что там нарисовано, у нас и так в продаже десяток типов валяется. Затычки в USB. Что ими делать — то?

      1. я сижу в чате http://easyelectronics.ru/chat
        если у тебя есть почта в гугле или яндыксе, или может жежешка, то можеш зайти туда под готовым акаунтом
        или зарегить жабер

        надо будет в бложике написать статью про покупку в дх
        хотя их уже достаточно написано

  2. Почитал и удивился — дополнительно инициализировались регистры, которые не были описаны в даташите.

    Вот за такие вещи производителей надо расстреливать в детстве. Из танка.

  3. Вообще-то этот модуль не является полноценным модулем ZigBee, поэтому он и вдвое дешевле, чем полноценные модули вроде XBee. Этот модуль рализует протокол более низкого уровня IEEE 802.15.4-2003, на котором в числе прочих базируется и ZigBee. Для работы собственно через протокол ZigBee (например, с другими девайсами, работающими через этот протокол), нужна еще его программная реализация в микроконтроллере, который работает с этим модулем. Microchip предоставляет такую реализацию, заточеную под свои Пики.

    http://en.wikipedia.org/wiki/Zigbee

    1. Честно говоря, не понял вопрос. Этот модуль — трансивер. То есть приемник и передатчик в одном флаконе. Управляется и передает данные по SPI. А вот что к SPI подключено — микроконтроллер с переходником на USB или сразу комп — трансиверу безразлично.

    1. Могу. Но потом возникнет вопрос — выложи spi.c ;) поэтому выложу сразу его:
      #include «spi.h»

      void SPI_master_init() {
      SPI_DDR &= ~_BV(SPI_P_MISO);
      SPI_DDR |= (_BV(SPI_P_MOSI) | _BV(SPI_P_SCK) | _BV(SPI_P_SS));
      SPI_PORT |= _BV(SPI_P_SS);
      SPCR = _BV(SPE) | _BV(MSTR);
      SPSR = _BV(SPI2X);
      }

      uint8_t SPI_master_write(uint8_t cData) {
      /* Start transmission */
      SPDR = cData;

      /* Wait for transmission complete */
      while (!SPSR & _BV(SPIF));
      return SPDR;
      }

  4. по ходу spi.h для меги8 должен виглядеть так:
    #define SPI_P_SCK PINB5;
    #define SPI_P_MISO PINB4;
    #define SPI_P_MOSI PINB3;
    #define SPI_P_SS PINB2;
    #define SPI_DDR DDRB;
    #define SPI_PORT PORTB;

    ток мне не понятно что такое _BV()…

  5. интересно)…а вот только я не понял как так
    *Вай-фай. Не более 32 устройств в сети. Не подошел. ??? сам дипломный проект на подобную тему пишу,только у меня объемы передаваемых данных по больше будут и на 200 устроиств в сети)))

    1. Подробно в стандарт не лез. По разным источникам в режиме ad-hoc могут работать от 32 до 256 устройств. Но все в один голос говорят — 5-6 и все ложится. А у меня именно ad-hoc

  6. А как проверить что пакет выслался без второго модуля? Т.е. модуль как-то нам ответит положительно, что мол да — пакетик поплыл по несущей, или всетаки нужно ловить пакет на втором модуле, чтобы быть увереным что с посылкой все налажено?

  7. Вот и я с этим модулем разбираюсь. Прошла неделя (или больше) как я тока записал и прочёл в регистр MRF_PACON2 значение 0х98. Неважно в принципе в какой регистр и какое значение а важно шо хоть от модуля каке то обратная реакция пошла.
    uint8_t SPI_master_write(uint8_t cData) {
    /* Start transmission */
    SPDR = cData;

    /* Wait for transmission complete */
    while (!SPSR & _BV(SPIF)); // Я НЕ ЗНАЮ КАК В ДРУГИХ КОМПИЛЯТОРАХ НО ТУТ ОШИБКА
    return SPDR;
    }

    unsigned char SPI_master_write(unsigned char cData)
    {
    /* Start transmission */
    SPDR = cData;
    /* Wait for transmission complete */
    while (!(SPSR &(1<<SPIF)));
    return SPDR;
    } должно быть так

  8. ==========================
    Для того, чтобы прочитать (или записать) один байт из внутренней памяти чипа, необходимо затратить 24 такта SPI.
    При частоте МК 8 Мгц, делителе частоты SPI = 4, получается скорость передачи (и
    приема) не более 8 Кб в секунду.
    ==========================

    Я расчетов не пойму. 8мгц=8000000 гц/24/4 = 83333/1024 = 81.38 кбайт, но не 8кбайт!
    Или я неправильно что то понял?

    1. Гыгы, побуду некропостером :)
      8000000 гц/24/4 = 83333 БИТ/с, а не байт/с — интерфейс-то последовательный. соответствено в байтах будет примерно в 10 раз меньше.

  9. Откуда берутся значения для этих данных :

    MRF_write_l(0x002, 0b01100001); /* last byte of packet (the LSB of the frame control p112 of IEEE 802.15.4-2003) — Data packet, no security, no frame pending, ACK requested, intra-pan transmission */

    MRF_write_l(0x003, 0xCC); /* first byte of packet (the MSB of the frame control p112 of IEEE 802.15.4-2003), use long addresses for both cases */

    MRF_write_l(0x004, 0x01); // IEEE sequence number //
    MRF_write_l(0x005, 0xFF); // PANID — broadcast //
    MRF_write_l(0x006, 0xFF); // PANID — broadcast //

  10. Доброго времени суток! Я, скурив даташит, ничего, что касается кода, не нашел. Может читал не тот документ? В статье речь идет не об этом документе DS70329B MRF24J40MA Data Sheet ? В каком документе можно посмотреть пример инициализации, адреса регистров и прочею инфу. Пытаюсь заставить работать этот модуль с паре с STM32.

Добавить комментарий