SMAC with Processor Expert

Freescale offers a free wireless SMAC stack  for their ZigBee and IEEE802.15.4 transceivers as found in the MC1321x (SRB and NCB) wireless kits, or as used on the MC13201 daughter card. The ‘S’ in SMAC stands for ‘Simple’. But it is not that simple to use that stack. So that’s why I’m using it transformed into a Processor Expert components. I have received recently requests and questions about it, and finally it is available on this site. If you are wondering for what it can be used, then read this post.

Created Tower Radio Card with MC13201 daughter board, SD card and Realtime Clock

Created Tower Radio Card with MC13201 daughter board, SD card and Realtime Clock

The stack is using the Freescale SMAC stack as base, and consists of four components: MC13192, SSEC, SPHY and SMAC. This post provides hopefully an entry point how to use them.

MC1321x SRB Board

Using the stack is as easy as adding the SMAC component to the project and configuring it with all the sub-components. I’m using here screenshots for the SRB MC1321x board:

MC13213 SRB Board

MC13213 SRB Board

The stack should work on any S08 microcontroller without any issues. I’m having the stack running as well on a ColdFire V1 and V2. Other ColdFire will need changed settings and have not been tested. Kinetis will not work (yet) as it is using a different Processor Expert concept.

MC13192 Transceiver Component

The most important settings are for the transceiver MC13192:

Transceiver Component: MC13192 as part of the SMAC

Transceiver Component: MC13192 as part of the SMAC

The transceiver is using an SPI connection plus other signals:

Microcontroller Transceiver Connection

Microcontroller Transceiver Connection

So for the SRB the pins are configured like this:

SRB SPI Configuration

SRB SPI Configuration

For the SPI protocol I have the choice to use a hardware SPI or software SPI: for the later bit-banging and general purpose pins can be used. As the SPI bus can be used for other peripherals, the transceiver component supports ‘gear shifting’: the SynchroMaster SPI component (‘SM1’ below) supports a ‘list of values’ with multiple speeds. As the transceiver maximum speed is 5 MHz, the transceiver is using an index into the list of values index table to reference the correct speed:

Gear Shifting with HW SPI

Gear Shifting with HW SPI

That way multiple slaves can share the same SPI bus with different speeds.

The other thing is to set the Wait interface, to configure the right transceiver type, to pull-up the IRQ (Interrupt Request) line and to configure the optional clock-out signal:

SRB Transceiver Configuration

SRB Transceiver Configuration

An open problem is to acknowledge an interrupt from the IRQ pin. The Processor Expert ExtInt Component unfortunately does not offer an interface to acknowledge it, so I had to workaround this with a macro solution which supports S08, ColdFire V1 (CN128) and ColdFire V2:

IRQ Macros

IRQ Macros

SMAC Events

The SMAC component will create events for Reset and Data packets coming in:

SMAC Events

SMAC Events

With that, the normal SMAC demos as delivered in the Freescale SMAC stack can be used.

Radio.h and Radio.c

I have usually a Radio.c which handles the transceiver part of the application for me. Radio.h declares the interface:

/**
* \file
* \brief Radio Module
* \author Erich Styger
*
* Interface to handle everything around the radio transceiver
*/

#ifndef RADIO_H_
#define RADIO_H_

#include "Platform.h"

#if PL_HAS_RADIO

#include "FSSH1.h"
#include "SMAC1.h"
#include "Event.h"

/*! \brief Event called in case of radio transceiver reset */
void RADIO_ResetIndication(void);

/*!
* \brief Event called on reception of a data packet
* \param[in] sRxPacket Pointer to the data packet received
*/
void RADIO_DataIndicationPacket(tRxPacket *sRxPacket);

/*!
* \brief Parses a command
* \param cmd Command string to be parsed
* \param handled Sets this variable to TRUE if command was handled
* \param io I/O stream to be used for input/output
* \return Error code, ERR_OK if everything was fine
*/
uint8_t RADIO_ParseCommand(const char *cmd, bool *handled, const FSSH1_StdIOType *io);

/*!
* \brief Event handler for Radio events. Needs to be called as part of the normal event handling
* \param[in] event Event to be processed
*/
void RADIO_AppHandleEvent(EVNT_Handle event);

/*! \brief Handler to deal with the Radio state machine. Needs to be called periodically to advance the state machine */
void RADIO_Handle(void);

/*!
* \brief Sends a data packet trough the Radio
* \param[in] data Data to be sent (binary), zero terminated
*/
void RADIO_SendString(const char *data);

void RADIO_SendStringRaw(const char *data);

/*! \brief Radio driver initialization */
void RADIO_Init(void);

#endif /* PL_HAS_RADIO */

#endif /* RADIO_H_ */

Radio.c implements the radio state machine, the radio command line interface and all the callbacks:

/**
* \file
* \brief Radio Module
* \author Erich Styger, erich.styger@hslu.ch
*
* Implementation of the Radio module to handle everything around the radio transceiver
*/

#include "Platform.h"
#if PL_HAS_RADIO
#include "SMAC1.h"
#include "UTIL1.h"
#include "Radio.h"
#include "Event.h"
#include "LED.h"
#include "FSSH1.h"
#include "FRTOS1.h"
#include "UTIL1.h"
#include "Shell.h"
#if PL_HAS_REMOTE
#include "Remote.h"
#endif

/* Radio state definitions */
typedef enum RADIO_AppStatusKind {
  RADIO_INITIAL_STATE,
  RADIO_RESET_STATE,
  RADIO_RECEIVER_ALWAYS_ON,
  RADIO_TRANSMIT_DATA,
  RADIO_WAITING_FOR_ACK,
  RADIO_TRANSMIT_ACK,
  RADIO_READY_FOR_TX_RX_DATA
} RADIO_AppStatusKind;

#define RADIO_QUEUE_NOF_ITEMS  8 /* number of items in the queue */
#define RADIO_QUEUE_ITEM_SIZE  32 /* size of each queue item */
static xQueueHandle RADIO_MsgQueue; /* queue for messages,  format is: kind(8bit) dataSize(8bit) data */

typedef enum RADIO_QueueMsgKind {
  RADIO_QUEUE_MSG_SNIFF, /* sniffing message */
  RADIO_QUEUE_MSG_ACCEL  /* acceleration message */
} RADIO_QueueMsgKind;

/*! \todo RADIO: Define here your PAN ID and acknowledge message you want to use */
#define RADIO_PREFIX_STR "EST"   /* prefix used for every message */
#define RADIO_ACK_STR    "ack"   /* acknowledge string */

#define RADIO_TIMEOUT_COUNT    0xB000 /*!< how long the timeout value will be while transmitting a message */

static RADIO_AppStatusKind RADIO_AppStatus = RADIO_INITIAL_STATE;
static uint8_t RADIO_Channel = 5;
static uint8_t RADIO_OutputPower = 15;
static bool RADIO_isOn = TRUE;
static bool RADIO_isSniffing = FALSE;

static tRxPacket RADIO_RxPacket;            /*!< SMAC structure for RX packets */
static uint8_t RADIO_RxDataBuffer[SMAC1_RADIO_BUF_SIZE]; /*!< Data buffer to hold RX data */

static tTxPacket RADIO_TxPacket;            /*!< SMAC structure for TX packets */
static uint8_t RADIO_TxDataBuffer[SMAC1_RADIO_BUF_SIZE]; /*!< Data buffer to hold TX data */

/*!
\brief A simple state machine iterating through different transceiver states
*/
static void RADIO_HandleState(void) {
  tTxPacket ackTxPacket;  /* SMAC structure for TX packets   */
  static uint8_t ackTxDataBuffer[SMAC1_RADIO_BUF_SIZE];    /*Data buffer to hold TX data */

  switch (RADIO_AppStatus) {
  case RADIO_INITIAL_STATE:
    RADIO_AppStatus = RADIO_RECEIVER_ALWAYS_ON;
    break;

  case RADIO_RECEIVER_ALWAYS_ON:
    RADIO_AppStatus = RADIO_READY_FOR_TX_RX_DATA;
    (void)SMAC1_MLMERXEnableRequest(&RADIO_RxPacket, 0); /* Zero means wait forever with RX ON. */
    break;

  case RADIO_READY_FOR_TX_RX_DATA: /* we are ready to receive/send data data */
    break;

  case RADIO_TRANSMIT_DATA:
    if (SMAC1_MLMERXDisableRequest() != SMAC1_SUCCESS) { /* Turn off the RX forever mode. */
      RADIO_AppStatus = RADIO_TRANSMIT_DATA; /* retry */
      break;
    }
    LED1_Neg();
    if ((SMAC1_MCPSDataRequest(&RADIO_TxPacket) == SMAC1_SUCCESS)) { /* transmit data */
      RADIO_AppStatus = RADIO_WAITING_FOR_ACK;
      (void)SMAC1_MLMERXEnableRequest(&RADIO_RxPacket, RADIO_TIMEOUT_COUNT);
    } else {
      RADIO_AppStatus = RADIO_RECEIVER_ALWAYS_ON; /* what should we otherwise do? */
    }
    break;

  case RADIO_TRANSMIT_ACK:
    /* Initialize the packet .*/
    /*! \todo RADIO: Below we send back the acknowledge message:
     *        check that your RADIO_ACK_STR is what you want and need.
     *        Notice the implicit string concatenation for efficiency and reduced code size. */
    UTIL1_strcpy((char*)ackTxDataBuffer, sizeof(ackTxDataBuffer), RADIO_PREFIX_STR RADIO_ACK_STR);
    ackTxPacket.pu8Data = &ackTxDataBuffer[0]; /* Load the address of our txbuffer into the tx structure*/
    ackTxPacket.u8DataLength = (byte)(UTIL1_strlen((char*)ackTxDataBuffer)+1); /* set the size of the packet */
    (void)SMAC1_MCPSDataRequest(&ackTxPacket); /* transmit data */
    RADIO_AppStatus = RADIO_RECEIVER_ALWAYS_ON;
    break;

  case RADIO_RESET_STATE:
    /* MC13192 Reset, reinitialize and return to default state.   */
    SMAC1_RadioInit();
    RADIO_AppStatus = RADIO_INITIAL_STATE;
    break;

  case RADIO_WAITING_FOR_ACK:
    /* At this point only two things happen, 1-we receive the ack packet or 2-timeout.
     * Either way the TX will leave this state and continue. Low power mode could be placed here
     * because both 1 and 2 are interrupt driven, in this case we keep it simple
     */
    break;

  default:
    break;
  }
}

static void QueueMessage(uint8_t kind, const char *msg, uint8_t msgSize) {
  /* format is: kind(8bit) dataSize(8bit) data */
  uint8_t i, buf[RADIO_QUEUE_ITEM_SIZE];
  signed portBASE_TYPE pxHigherPriorityTaskWoken;

  buf[0] = kind;
  buf[1] = msgSize;

  i = 2;
  while(msgSize>0 && i<sizeof(buf)) {
    buf[i++] = *msg;
    msg++;
    msgSize--;
  }
  if (FRTOS1_xQueueSendToBackFromISR(RADIO_MsgQueue, &buf[0], &pxHigherPriorityTaskWoken)!=pdTRUE) {
    /* was not able to send to the queue. Well, not much we can do here... */
  }
}

void RADIO_DataIndicationPacket(tRxPacket *sRxPacket) {
  if (sRxPacket->u8Status==SMAC1_TIMEOUT) {      /* Put timeout condition code here */
    LED1_Neg(); LED2_Neg();  /* indicator for bad or no communication */
    EVNT_SetEvent(EVNT_RADIO_TIMEOUT);
  } else if (sRxPacket->u8Status == SMAC1_SUCCESS) { /* good packet received: handle it. */
    if (RADIO_isSniffing) {
      QueueMessage(RADIO_QUEUE_MSG_SNIFF, (const char*)sRxPacket->pu8Data, sRxPacket->u8DataLength);
    }
    /* check if it is the packet we expect...*/
    if (   RADIO_AppStatus==RADIO_WAITING_FOR_ACK
      && UTIL1_strncmp((char*)sRxPacket->pu8Data, RADIO_PREFIX_STR RADIO_ACK_STR, sizeof(RADIO_PREFIX_STR RADIO_ACK_STR)-1)==0
      ) /* is it our acknowledge packet? */
    {
      EVNT_SetEvent(EVNT_RADIO_ACK);
    } else if (UTIL1_strncmp((char*)sRxPacket->pu8Data, RADIO_PREFIX_STR, sizeof(RADIO_PREFIX_STR)-1)==0) {
      QueueMessage(RADIO_QUEUE_MSG_ACCEL, (const char*)sRxPacket->pu8Data, sRxPacket->u8DataLength);
      EVNT_SetEvent(EVNT_RADIO_DATA);
    } else { /* unknown packet? */
      EVNT_SetEvent(EVNT_RADIO_UNKNOWN);
    }
  } else if (sRxPacket->u8Status==SMAC1_OVERFLOW) { /* received packet, but it was longer than what we expect. */
    EVNT_SetEvent(EVNT_RADIO_OVERFLOW);
    LED1_Neg(); LED2_Neg(); /* indicator for bad or no communication */
  }
}

void RADIO_ResetIndication(void) {
  EVNT_SetEvent(EVNT_RADIO_RESET);         /* MC13192 reset, re-initialize.*/
}

void RADIO_AppHandleEvent(EVNT_Handle event) {
  switch(event) {
    case EVNT_RADIO_RESET: /* radio transceiver has reset */
      SHELL_SendMessage("RADIO reset\r\n");
      RADIO_AppStatus = RADIO_RESET_STATE;
      break;
    case EVNT_RADIO_TIMEOUT: /* packet sent was causing timeout */
      SHELL_SendMessage("RADIO timeout\r\n");
      RADIO_AppStatus = RADIO_RECEIVER_ALWAYS_ON;
      break;
    case EVNT_RADIO_ACK: /* acknowledge received */
      SHELL_SendMessage("RADIO rx ack\r\n");
      RADIO_AppStatus = RADIO_RECEIVER_ALWAYS_ON;
      break;
    case EVNT_RADIO_OVERFLOW: /* packet received was too long */
      SHELL_SendMessage("RADIO overflow\r\n");
      RADIO_AppStatus = RADIO_RECEIVER_ALWAYS_ON;
      break;
    case EVNT_RADIO_DATA: /* data received */
      SHELL_SendMessage("RADIO rx data, going to tx ACK\r\n");
      RADIO_AppStatus = RADIO_TRANSMIT_ACK;
      break;
    case EVNT_RADIO_UNKNOWN: /* unknown package received */
      SHELL_SendMessage("RADIO unknown\r\n");
      RADIO_AppStatus = RADIO_RECEIVER_ALWAYS_ON;
      break;
  } /* switch */
}

/*!
* \brief Sends a data packet trough the Radio
* \param[in] data Data to be sent (binary), zero terminated
*/
void RADIO_SendString(const char *data) {
  if (!RADIO_isOn) {
   return;
  }
  while (RADIO_AppStatus != RADIO_READY_FOR_TX_RX_DATA) { /* we are not ready yet! */
    RADIO_HandleState(); /* advance state machine */
  }
  UTIL1_strcpy((char*)RADIO_TxDataBuffer, sizeof(RADIO_TxDataBuffer), RADIO_PREFIX_STR);
  UTIL1_strcat((char*)RADIO_TxDataBuffer, sizeof(RADIO_TxDataBuffer), data);
  RADIO_TxPacket.pu8Data = &RADIO_TxDataBuffer[0];            /* Load the address of our txbuffer into tx structure.*/
  RADIO_TxPacket.u8DataLength = (byte)(UTIL1_strlen((char*)RADIO_TxDataBuffer)+1); /* Set the data length of the packet */
  RADIO_AppStatus = RADIO_TRANSMIT_DATA;
  RADIO_HandleState(); /* advance state machine */
}

void RADIO_SendStringRaw(const char *data) {
  if (!RADIO_isOn) {
    return;
  }
  while (RADIO_AppStatus != RADIO_READY_FOR_TX_RX_DATA) { /* we are not ready yet! */
    RADIO_HandleState(); /* advance state machine */
  }
  UTIL1_strcpy((char*)RADIO_TxDataBuffer, sizeof(RADIO_TxDataBuffer), data);
  RADIO_TxPacket.pu8Data = &RADIO_TxDataBuffer[0];            /* Load the address of our txbuffer into tx structure.*/
  RADIO_TxPacket.u8DataLength = (byte)(UTIL1_strlen((char*)RADIO_TxDataBuffer)+1); /* Set the data length of the packet */
  RADIO_AppStatus = RADIO_TRANSMIT_DATA;
  RADIO_HandleState(); /* advance state machine */
}

/*!
* \brief Sets the channel number to be used
* \param ch The channel to be used, in the range 0..15
*/
static void RADIO_SetChannel(uint8_t ch) {
  RADIO_Channel = ch&0xF; /* make sure it remains in range 0..15 */
  (void)SMAC1_MLMESetChannelRequest(RADIO_Channel);  /* Set channel */
}

/*!
* \brief Sets the channel number to be used
* \param power The channel to be used, in the range 0..15
*/
static void RADIO_SetOutputPower(uint8_t power) {
  RADIO_OutputPower = power&0xF; /* make sure it remains in range 0..15 */
  (void)SMAC1_MLMEMC13192PAOutputAdjust(RADIO_OutputPower); /* Set output power setting */
}

static void RADIO_PrintHelp(const FSSH1_StdIOType *io) {
  FSSH1_SendHelpStr("radio", "Group of radio commands\r\n", io->stdOut);
  FSSH1_SendHelpStr("  help|status", "Shows radio help or status\r\n", io->stdOut);
  FSSH1_SendHelpStr("  on|off", "Turns the radio on or off\r\n", io->stdOut);
  FSSH1_SendHelpStr("  sniff on|off", "Turns packet sniffing on or off\r\n", io->stdOut);
  FSSH1_SendHelpStr("  channel ", "Switches to the given channel. Channel must be in the range 0..15\r\n", io->stdOut);
  FSSH1_SendHelpStr("  power ", "Changes the output power. Power must be in the range 0..15\r\n", io->stdOut);
  FSSH1_SendHelpStr("  send ", "Send a string using the wireless transceiver\r\n", io->stdOut);
}

static void RADIO_PrintStatus(const FSSH1_StdIOType *io) {
  short dBm;
  unsigned char link_quality;  /* Holds the link quality of the last received Packet.*/

  FSSH1_SendStatusStr("Radio", "\r\n", io->stdOut);
  FSSH1_SendStatusStr("  transceiver", RADIO_isOn?"on\r\n":"off\r\n", io->stdOut);
  FSSH1_SendStatusStr("  sniffing", RADIO_isSniffing?"on\r\n":"off\r\n", io->stdOut);
  link_quality = SMAC1_MLMELinkQuality();  /* Read the link quality of the last received packet.*/
  dBm = (short)(-(link_quality/2));
  FSSH1_SendStatusStr("  LQ", "", io->stdOut); FSSH1_SendNum16s(dBm, io->stdOut); FSSH1_SendStr(" dBm\r\n", io->stdOut);
  FSSH1_SendStatusStr("  channel", "", io->stdOut); FSSH1_SendNum16u((uint16_t)RADIO_Channel, io->stdOut); FSSH1_SendStr("\r\n", io->stdOut);
  FSSH1_SendStatusStr("  outputPower", "", io->stdOut); FSSH1_SendNum16u((uint16_t)RADIO_OutputPower, io->stdOut); FSSH1_SendStr("\r\n", io->stdOut);
  FSSH1_SendStatusStr("  PAIND", RADIO_PREFIX_STR, io->stdOut); FSSH1_SendStr("\r\n", io->stdOut);
  FSSH1_SendStatusStr("  ACK", RADIO_ACK_STR, io->stdOut); FSSH1_SendStr("\r\n", io->stdOut);
}

uint8_t RADIO_ParseCommand(const char *cmd, bool *handled, const FSSH1_StdIOType *io) {
  uint8_t res = ERR_OK;
  long val;
  const char *p;

  if (UTIL1_strcmp(cmd, FSSH1_CMD_HELP)==0 || UTIL1_strcmp(cmd, "radio help")==0) {
    RADIO_PrintHelp(io);
    *handled = TRUE;
  } else if (UTIL1_strcmp(cmd, FSSH1_CMD_STATUS)==0 || UTIL1_strcmp(cmd, "radio status")==0) {
    RADIO_PrintStatus(io);
    *handled = TRUE;
  } else if (UTIL1_strcmp(cmd, "radio on")==0) {
    RADIO_isOn = TRUE;
    *handled = TRUE;
  } else if (UTIL1_strcmp(cmd, "radio off")==0) {
    RADIO_isOn = FALSE;
    *handled = TRUE;
  } else if (UTIL1_strcmp(cmd, "radio sniff on")==0) {
    RADIO_isSniffing = TRUE;
    *handled = TRUE;
  } else if (UTIL1_strcmp(cmd, "radio sniff off")==0) {
    RADIO_isSniffing = FALSE;
    *handled = TRUE;
  } else if (UTIL1_strncmp(cmd, "radio channel", sizeof("radio channel")-1)==0) {
    p = cmd+sizeof("radio channel");
    if (UTIL1_xatoi(&p, &val)==ERR_OK && val>=0 && val<=15) {
      RADIO_SetChannel((uint8_t)val);
      *handled = TRUE;
    } else {
      FSSH1_SendStr("Wrong argument, must be in the range 0..15\r\n", io->stdErr);
      res = ERR_FAILED;
    }
  } else if (UTIL1_strncmp(cmd, "radio power", sizeof("radio power")-1)==0) {
    p = cmd+sizeof("radio power");
    if (UTIL1_xatoi(&p, &val)==ERR_OK && val>=0 && val<=15) {
      RADIO_SetOutputPower((uint8_t)val);
      *handled = TRUE;
    } else {
      FSSH1_SendStr("Wrong argument, must be in the range 0..15\r\n", io->stdErr);
      res = ERR_FAILED;
    }
  } else if (UTIL1_strncmp(cmd, "radio send", sizeof("radio send")-1)==0) {
    p = cmd+sizeof("radio send");
    RADIO_SendString(p);
    *handled = TRUE;
  }
  return res;
}

/*!
\brief This routine is called as callback by the radio driver on reception of a data packet
\param msg Pointer to the message we received.
*/
static void RADIO_HandleMessage(uint8_t *msg) {
  char buf[32];
  uint8_t i, size;

  if (RADIO_isSniffing && *msg==RADIO_QUEUE_MSG_SNIFF) {
    msg++;
    size = *msg++;
    UTIL1_strcpy(buf, sizeof(buf), "\r\nch #:"); /* use new line at the beginning, as the hex dump at the end might be fill up buffer completely */
    UTIL1_strcatNum16s(buf, sizeof(buf), RADIO_Channel);
    UTIL1_strcat(buf, sizeof(buf), " size:");
    UTIL1_strcatNum16s(buf, sizeof(buf), size);
    UTIL1_strcat(buf, sizeof(buf), " ASCII: ");
    SHELL_SendMessage(buf);
    buf[0] = '\0';
    /* write as string */
    for(i=0;i
      UTIL1_chcat(buf, sizeof(buf), msg[i]);
    }
    SHELL_SendMessage(buf);
    /* write as hex */
    buf[0] = '\0';
    UTIL1_strcat(buf, sizeof(buf), " hex: ");
    for(i=0; i<size;i++) {
      UTIL1_strcatNum8Hex(buf, sizeof(buf), msg[i]);
      UTIL1_strcat(buf, sizeof(buf), " ");
    }
    SHELL_SendMessage(buf);
    SHELL_SendMessage("\r\n");
  }
}

/*! \brief Radio application state machine */
void RADIO_Handle(void) {
  uint8_t buf[RADIO_QUEUE_ITEM_SIZE];

  if (RADIO_isOn) {
    RADIO_HandleState(); /* advance state machine */
  }
  /* poll radio message queue */
  if (FRTOS1_xQueueReceive(RADIO_MsgQueue, buf, 0)==pdPASS) {
    /* received message from queue */
    RADIO_HandleMessage(buf);
  }
}

void RADIO_Init(void) {
  (void)SMAC1_MLMESetMC13192ClockRate(0);    /* Set initial Clk speed from transceiver (CLKO)*/
  RADIO_SetChannel(RADIO_Channel);           /* Set channel */
  RADIO_SetOutputPower(15);                  /* Set output power */

  /* Initialize the packet */
  RADIO_TxPacket.u8DataLength = 0;               /* Set TX default length to 0 */
  RADIO_TxPacket.pu8Data = &RADIO_TxDataBuffer[0]; /* Load the address of our txbuffer into the tx structure */

  RADIO_RxPacket.u8DataLength = 0;               /* Set RX default to 0*/
  RADIO_RxPacket.pu8Data = &RADIO_RxDataBuffer[0];  /* Load the address of our rxbuffer into rx structure */
  RADIO_RxPacket.u8MaxDataLength = 24;           /* Define the max buffer we are interested in */
  RADIO_RxPacket.u8Status = TRSVR1_INITIAL_VALUE;  /* initialize the status packet to 0 */

  RADIO_AppStatus = RADIO_INITIAL_STATE;        /* Set the initial status of the application state variable */
  /* create data queue */
  RADIO_MsgQueue = FRTOS1_xQueueCreate(RADIO_QUEUE_NOF_ITEMS, RADIO_QUEUE_ITEM_SIZE);
  if (RADIO_MsgQueue==NULL) { /* queue creation failed! */
    for(;;) {} /* not enough memory? */
  }
}
#endif

Components

The components are available on the embedded component web site: MC13192, SSEC, SPHY and SMAC. I have implemented an application for the SRB with operating system, LED’s and many other components available using the SMAC stack. If there is interest, I can make it available.

Happy transceiving 🙂

11 thoughts on “SMAC with Processor Expert

  1. Pingback: Freedom Track Robot with IEEE802.15.4/SMAC | MCU on Eclipse

  2. Pingback: Tracked Robot Update: Ultrasonic, Line Sensor and Shell with SMAC 802.15.4 | MCU on Eclipse

  3. Pingback: Zumo Robot assembled | MCU on Eclipse

  4. Pingback: RNet: A Simple Open Source Radio Network Stack | MCU on Eclipse

  5. Pingback: IEEE802.15.4 for the Zumo Robot | MCU on Eclipse

  6. Pingback: RNet Stack for 8bit MC9S08QE128 Microcontroller and MC13201 Transceiver | MCU on Eclipse

  7. Hi.

    I would like to ask on Freescale’s wireless SMAC stack for ZigBee and IEEE802.15.4 transceivers over MC1323x family.
    Your post refers to the MC1321x family, so I will understand if you don’t have a full answer to my question, but I will nevertheless give it a try…

    First of all, allow me to start with a side note on this issue.
    I have previously reported a bug where, upon RX the PHY overrides CPU memory (by writing an amount of data larger than the designated buffer).
    This happens when the MAX_FRAME_LENGTH register is set to its maximum permitted value of 127.
    Again, this is possibly relevant only for the MC1323x family, but a full description of the problem and the solution can be found at https://community.nxp.com/thread/379595.

    My actual question is how to deploy a ZigBee network in which:
    1. MAC frames are filtered at the PHY layer according to source/destination address.
    2. MAC frames are acknowledged at the PHY layer.

    The MC1323x clearly states that both features are supported.
    However, the free SMAC-Stack source code does not seem to support either one of these features.

    So at present:
    1. We filter every received packet at the application layer, i.e., we embed a 16-bit destination address within the transmitted packet payload, and check it upon reception.
    2. We acknowledge every received packet at the application layer.

    This is not very efficient of course, as the application is “interrupted for nothing” whenever a frame with the wrong address is received.

    The MC1323x data-sheet is rather obscure on how to implement the frame-filtering and frame-acknowledgement functionalities.
    I have posted a detailed question on the frame-filtering issue, at https://community.nxp.com/message/826864, but responses there are “not very eminent” (to say the least).

    So on a parallel route, I would like to explore the option of an off-the-shelf solution.
    Would you happen to be aware of any (not necessarily free) source package, which supports ZigBee network to a better extent than the free SMAC-Stack that you mention in your post (including the specific functionalities that I have referred to)?

    Thank you for your time 🙂

    Like

    • Hi Barak,
      I only can comment on my experience with SMAC and ZigBee/IEEE802.15.4 on the MC1321x family, as I have not used/moved to the MC1323x, mainly because of the things I saw with the MC1323x.
      I explored the IEEE802.15.4 and ZigBee stack, but only a library version was provided, not the sources. That’s why I sticked with the SMAC as this one was open. For both the IEEE802.15.4 and ZigBee the specs says that things like address filtering *could* be done at the PHY level, but the implementation did it at the MAC level (which was not an issue for me). In the case of the MC1321x, the hardware/PHY implementation in the transceiver would not had that possiblity anyway. What you describe (filter and acknowledge) is what I typically do too, except if the hardware (for example the nRF24L01+ can do this to some extend) offers filtering. You say you do that at the application level. To me this is too high: you should do this in the MAC (acknowledge) and in the NWK (Network) layer for the address filtering. See https://mcuoneclipse.com/2013/11/17/rnet-a-simple-open-source-radio-network-stack/ how I do this (RNet runs as well on the MC1321x). I stopped exploring ZigBee a while back because its main benfit (interoperability) simply did not work out well. So I cannot comment on free ZigBee solution. But what I have explored recently and which looks reasonable is the RadioHead library (check the licensing terms): http://platformio.org/lib/show/124/RadioHead. It works for me for Nordic Semiconductora and Semtech LoRa transceivers. If you are interested in this one, let me know.
      I hope this helps,
      Erich

      Like

      • Hi Eric.

        Thank you for your quick response!

        When I said “at the application layer”, I meant to say that in general we handle it in the CPU (rather than offloading it to the PHY). Of course, our application is divided into MAC/Network/App layers, and packet assembling/stripping/acknowledgement is handled below the App layer.

        But main core (i.e., the application) is still buy doing these things, which is why I was hoping I could offload it to the PHY itself.

        I will nevertheless have a look at the open source that you’ve mentioned, and see if it makes sense for me to adopt it.
        I pretty much had to implement the entire Network layer myself, and tweak the MAC layer (the SMAC source code) in certain places for our specific needs.
        So I will be happy to see and consider a possibly better design scheme.

        Unfortunately at this point, replacing the HW is not an option, so I have no point in reviewing the RadioHead library that you have suggested.

        One question remaining – could you please elaborate on “the things I saw with the MC1323x”?

        Thanks again 🙂

        Like

        • I saw several things with the stack: I faced problems with interrupt reentrancy if the bus to the transceiver was shared with other devices. Additionally some variables seemed not properly initialized (memory/stack overflow/overwrite).

          Like

        • Yep, I’ve noticed some issues in the SMAC source code as well, including even spelling errors (e.g. ‘Lenght’ instead of ‘Length’), which IMO indicated low-quality of the code (or a complete lack of code review). So I get your point. Thanks for help out though 🙂

          Like

What do you think?

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.