ZigBee Module Protocol Stack-Z-Stack Protocol Stack Foundation and Data Transfer Experiments

Keywords: Mac network

;

It took a long time to write.. It feels good.. If you look, look closely.. Mua~

Z-Stack Protocol Stack Base and Data Transfer Experiments

1. Experimental Purpose

End nodes send data wirelessly to the coordinator, which sends data to the PC through a serial port and displays it on the screen.Serial port optimization changes wired serial port transmission to wireless Bluetooth transmission.

 

2. Experimental Platform

Hardware: 2 zigbee nodes, 1 compiler, 1 Square to USB cable, and a Bluetooth module

Software: The experiment is based on the SamplleApp project.

 

3. EXPERIMENTAL STEPS

  1. Serial Initialization Code
  2. Send Part Code
  3. Receive Part Code

 

4. Protocol Stack Base

Learn a little about the protocol stack before doing the experiment.

What is a protocol stack?We know that Zigbee is generally used for networking and data transfer.It's conceivable that the number of code in it is so large that it would be a hassle if we had to write it ourselves every time we used zigbee.So there's a protocol stack.It can be said that it is a small operating system, encapsulating a lot of code such as communication, networking, etc.All we have to do is call functions to achieve our goal.

Take a look at the workflow of the protocol stack (Figure 1).Then I'll do a simple analysis of the protocol stack against the flowchart.

 

Figure 1

 

Let's start with the "Start" of the flowchart.

Open the project file SampleApp, the main function is the beginning of the program execution, we need to find it first.The Main function opens under ZMain.c in the ZMAin folder and finds the main function.

  1 int main( void )
  2 
  3 {
  4 
  5   // Turn off interrupts 
  6 
  7   //Close all interrupts
  8 
  9   osal_int_disable( INTS_ALL );
 10 
 11  
 12 
 13   // Initialization for board related stuff such as LEDs 
 14 
 15   //Initialize the system clock
 16 
 17   HAL_BOARD_INIT();
 18 
 19  
 20 
 21   // Make sure supply voltage is high enough to run 
 22 
 23   //Detect if chip voltage is normal
 24 
 25   zmain_vdd_check();
 26 
 27  
 28 
 29   // Initialize board I/O
 30 
 31   //Initialize peripherals
 32 
 33   InitBoard( OB_COLD );
 34 
 35  
 36 
 37   // Initialze HAL drivers
 38 
 39   //Initialize each hardware module of the chip
 40 
 41   HalDriverInit();
 42 
 43  
 44 
 45   // Initialize NV System
 46 
 47   //Initialization flash storage
 48 
 49   osal_nv_init( NULL );
 50 
 51  
 52 
 53   // Initialize the MAC
 54 
 55   //Initialization MAC layer
 56 
 57   ZMacInit();
 58 
 59  
 60 
 61   // Determine the extended address
 62 
 63   //Determine IEEE 64 Bit Address
 64 
 65   zmain_ext_addr();
 66 
 67  
 68 
 69 #if defined ZCL_KEY_ESTABLISH
 70 
 71   //Initialize the Certicom certificate information.
 72 
 73   zmain_cert_init();
 74 
 75 #endif
 76 
 77  
 78 
 79   // Initialize basic NV items
 80 
 81   //Initialize non-volatile variables
 82 
 83   zgInit();
 84 
 85  
 86 
 87 #ifndef NONWK
 88 
 89   // Since the AF isn't a task, call it's initialization routine
 90 
 91   afInit();
 92 
 93 #endif
 94 
 95  
 96 
 97   // Initialize the operating system
 98 
 99   //Initialize Operating System***********************************Initialization focus
100 
101   osal_init_system();
102 
103  
104 
105   // Allow interrupts
106 
107   //Allow interruption of enabling
108 
109   osal_int_enable( INTS_ALL );
110 
111  
112 
113   // Final board initialization
114 
115   //Initialization keys
116 
117   InitBoard( OB_READY );
118 
119  
120 
121   // Display information about this device
122 
123   //Display device information
124 
125   zmain_dev_info();
126 
127  
128 
129   /* Display the device info on the LCD */
130 
131 #ifdef LCD_SUPPORTED
132 
133   zmain_lcd_init();
134 
135 #endif
136 
137  
138 
139 #ifdef WDT_IN_PM1
140 
141   /* If WDT is used, this is a good place to enable it. */
142 
143   WatchDogEnable( WDTIMX );
144 
145 #endif
146 
147  
148 
149   // No Return from here 
150 
151   // Execute the operating system and do not return after entering************************Operational focus
152 
153   osal_start_system(); 
154 
155  
156 
157   return 0;  // Shouldn't get here.
158 
159 }
main();

Looking at the main function, you can see that there are all kinds of initialization functions at the beginning, that is, the "various initialization functions" in the corresponding flowchart.One thing to note in initialization is that "osal_init_system();" initializes operating system functions.It will be explained later.Continue to read, "osal_start_system();" This is the execution of operating system functions, corresponding to the "running operating system" in the process.Note that this function does not return when it is entered.Summarizing the main function is to initialize and execute the operating system.

Let's take another look at osal_init_system(); this function, which initializes the operating system.Let's go to definition and look at the code for this function.

 1 uint8 osal_init_system( void )
 2 
 3 {
 4 
 5   // Initialize the Memory Allocation System
 6 
 7   // Initialize memory allocation system
 8 
 9   osal_mem_init();
10 
11  
12 
13   // Initialize the message queue
14 
15   // Initialize message queue
16 
17   osal_qHead = NULL;
18 
19  
20 
21   // Initialize the timers
22 
23   // Initialization timer
24 
25   osalTimerInit();
26 
27  
28 
29   // Initialize the Power Management System
30 
31   // Initialize power management system
32 
33   osal_pwrmgr_init();
34 
35  
36 
37   // Initialize the system tasks.
38 
39   // Initialize System Tasks**********************************A key
40 
41   osalInitTasks();
42 
43  
44 
45   // Setup efficient search for the first free block of heap.
46 
47   osal_mem_kick();
48 
49  
50 
51   return ( SUCCESS );
52 
53 }
osal_init_system();

Looking at this function, we can see that there are still various initialization functions.Focus on "osalInitTasks();" This function, the function is to initialize the task system, continue to go to definition, view the function.

 1 void osalInitTasks( void )
 2 
 3 {
 4 
 5   uint8 taskID = 0;
 6 
 7  
 8 
 9   //Allocate buffer memory, return pointer
10 
11   tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);
12 
13   //Set the allocated memory space unit value to 0
14 
15   osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));
16 
17  
18 
19   // Task priority ranks from high to low, with high priority corresponding taskID Small
20 
21   macTaskInit( taskID++ );  //0 Not to be considered
22 
23   nwk_init( taskID++ );     //1 |
24 
25   Hal_Init( taskID++ );     //2 |
26 
27 #if defined( MT_TASK )
28 
29   MT_TaskInit( taskID++ );
30 
31 #endif
32 
33   APS_Init( taskID++ );     //3 |
34 
35 #if defined ( ZIGBEE_FRAGMENTATION )
36 
37   APSF_Init( taskID++ );
38 
39 #endif
40 
41   ZDApp_Init( taskID++ );   //4 Need to be considered
42 
43 #if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )
44 
45   ZDNwkMgr_Init( taskID++ );
46 
47 #endif
48 
49   SampleApp_Init( taskID ); //5 Need to be considered*************************A key
50 
51                             //Usually initialize your own thing here
52 
53 }
osalInitTask();

From the comments we can see that this function was also initialized and that the code inside is a bit difficult to understand... here we need to know a little first, then we will mention it later, so let's explain it first.Well, since this is my own understanding, some of the descriptions may not be very professional, so it's good to understand this, and come back to modify it later when you're professional...The protocol stack uses a task mechanism and then uses polling to process tasks.That is, when it is idle, it starts with higher priority tasks, checks one by one for whether there are any tasks to process, handles the task, and continues circular detection if there are no tasks to process.

OK~That's it!Then, let's look at this function again. Its function is to give them an ID number according to their priority and initialize the task at the same time.Note that the higher the priority of the task, the smaller its ID number!Then those above we don't need to consider at all are the last two functions (we could have operated with the lowest priority...).Hmm... it feels like go ing to definition for a long time... don't look any further, and then read both functions in more detail.

This way, the initialized function is interpreted. Let's go back to the main function and continue with the next function, "osal_start_system();" to execute the operating system function!Come on, go on to definition to find it.

 1 void osal_start_system( void )
 2 
 3 {
 4 
 5 #if !defined ( ZBIT ) && !defined ( UBIT )
 6 
 7   for(;;)  // Forever Loop
 8 
 9 #endif
10 
11   {
12 
13     osal_run_system();
14 
15   }
16 
17 }
osal_start_system();

"Hmm, find"osal_run_system();"Let's continue...

 1 void osal_run_system( void )
 2 
 3 {
 4 
 5   uint8 idx = 0;
 6 
 7  
 8 
 9   osalTimeUpdate();        //Scan which event was triggered, set corresponding flag bit
10 
11   Hal_ProcessPoll();
12 
13  
14 
15   //Retrieve if a task needs to be processed starting at 0 (highest priority)
16 
17   //Others jump out of the loop immediately, not until the retrieval is complete
18 
19   do {
20 
21     if (tasksEvents[idx])  // Task is highest priority that is ready.
22 
23     {
24 
25       break;
26 
27     }
28 
29   } while (++idx < tasksCnt);
30 
31  
32 
33   //Analyze index numbers, process tasks, skip without tasks
34 
35   if (idx < tasksCnt)
36 
37   {
38 
39     uint16 events;
40 
41     halIntState_t intState;
42 
43  
44 
45     HAL_ENTER_CRITICAL_SECTION(intState);    //Enter critical zone, protect
46 
47     events = tasksEvents[idx];               //Extraction Task
48 
49     tasksEvents[idx] = 0;  // Clear the Events for this task.Clear Tasks
50 
51     HAL_EXIT_CRITICAL_SECTION(intState);     //Exit critical zone
52 
53  
54 
55     activeTaskID = idx;
56 
57     events = (tasksArr[idx])( idx, events ); //Call task handler via pointer********A key
58 
59     activeTaskID = TASK_NO_TASK;
60 
61  
62 
63     HAL_ENTER_CRITICAL_SECTION(intState);    //Enter critical zone
64 
65     tasksEvents[idx] |= events;  // Add back unprocessed events to the current task.
66 
67                                              //Save Unhandled Events
68 
69     HAL_EXIT_CRITICAL_SECTION(intState);     //Exit critical zone
70 
71   }
72 
73 #if defined( POWER_SAVING )
74 
75   else  // Complete pass through all task events with no activity?
76 
77   {
78 
79     osal_pwrmgr_powerconserve();  // Put the processor/system into sleep
80 
81   }
82 
83 #endif
84 
85  
86 
87   /* Yield in case cooperative scheduling is being used. */
88 
89 #if defined (configUSE_PREEMPTION) && (configUSE_PREEMPTION == 0)
90 
91   {
92 
93     osal_task_yield();
94 
95   }
96 
97 #endif
98 
99 }
osal_run_system();

Here's where I've been polling before~Let's talk about my understanding here...but I'm not sure it's right...The general idea should be right...

First divide the work into two parts, one part is the task request, and if there is a task request, place the corresponding flag at position 1.The other part is the function we see.At the beginning of the function, read the register of the task request (which may not be a register, in that sense), and then retrieve whether there is a task request in turn from the highest priority.As long as there are task requests, enter the processing task request section (that is, the contents of the if statement "if (idx < tasksCnt)) and continue the loop if there are No.There are two things to note in the Processing Task Request section: 1. It continues to detect whether there are still task requests after the high-priority task has been processed, until the processing of the request using the task has been completed.2. After a task is processed, it clears the flags of the task.

Well, I don't know if you understand... Then the main function here is the sentence "events = (tasksArr[idx]) (idx, events);".Let's first look at the definition of the tasksArr[] array.

 1 const pTaskEventHandlerFn tasksArr[] = {
 2 
 3   macEventLoop,
 4 
 5   nwk_event_loop,
 6 
 7   Hal_ProcessEvent,
 8 
 9 #if defined( MT_TASK )
10 
11   MT_ProcessEvent,
12 
13 #endif
14 
15   APS_event_loop,
16 
17 #if defined ( ZIGBEE_FRAGMENTATION )
18 
19   APSF_ProcessEvent,
20 
21 #endif
22 
23   ZDApp_event_loop,
24 
25 #if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )
26 
27   ZDNwkMgr_event_loop,
28 
29 #endif
30 
31   SampleApp_ProcessEvent
32 
33 };
pTaskEventHandlerFn tasksArr[]

Did you find it in the same file as the function osalInitTasks()?Did you find it on top of the osalInitTasks() function?Take a closer look and see if it defines member variable names in the same order as the initialization function below!Let's say it's still cloudy... (because I still don't fully understand it when I write here...) I'll explain the white dot again... Before, I didn't mean that every task has an ID number. Priority starts at 0, and the first index number in the array is also 0, which means that the task ID number corresponds to the array index number, so you can find the phase in the array by using the task ID number.Corresponding tasks.And it's amazing, at least how do I feel...................................................................................Just to understand, the type of the original array is a function!That is to say, find the corresponding function to process the task through the task ID!Do you understand that?I don't understand the message...Has anyone read it?Laugh...

Finally, the analysis of the protocol stack is complete... would it be confusing?Take a look at the flowchart below to review it again.

 

Figure 2

 

5. Experiments and Explanations

1. Serial initialization code

In the protocol stack, the folder App is the place where users add their own code.Open the file SampleApp.c and add code in the INCLUDES section

    #include "MT_UART.h"

 

Figure 3

Instructions for operation: There are two files in the protocol stack about serial port encapsulation, one is HAL->Target->CC2530EB->Drivers->hal_uart.c, the other is MT->MT_UART.c.What is the difference between the two files?Open the file to study.First, there is include "hal_uart.h" in MT_UART.c, so just write the header file "MT_UART.h".Then, look carefully at the code and analyze the file hal_uart.c. MT_UART.c is an operation on any serial port as long as the corresponding operation is selected for different serial port types.That is, MT_UART.c is a bit lower.

(2) In the same SampleApp.c file, find the function void SampleApp_Init (uint8 task_id) and add the serial initialization code to it.

/************Serial Initialization******************/

  MT_UartInit();                      //Serial port initialization

  MT_UartRegisterTaskID(task_id);     //Registration Task Number

 

Figure 4

Instructions for operation: Serial port initialization is not necessary.To register a task number is to register a serial event in SamplleApp_Init(); through task_id.SampleApp_Init() was mentioned earlier; the important function is to assign an ID number, which is also the lowest priority.To give the ID number of this function to the serial port is to tell the serial port that I initialized in this function, and the corresponding task priority is the lowest...

(3) Change serial initialization configuration.

The MT_UartInit() shown in the figure above; go to definition, and enter the MT_UartInit() function (Figure 5).Find MT_UART_DEFAULT_BAUDRATE and set the baud rate to 11520 after go to definition (Figure 6).

Go back to Figure 3, find MT_UART_DEFAULT_OVERFLOW, and go to definition set the parameter to FALSE (Figure 7).

 

Figure 5

Figure 6

 

Figure 7

Instructions: Modifying the baud rate will not explain.

  #define MT_UART_DEFAULT_OVERFLOW       FALSE

This line of code means to turn on serial flow control.Because our serial communication is two wires, it must be closed.

 

2. Send some code

(1) Open SampleApp.c and find the SampleApp event handler, SampleApp_ProcessEvent().

Additionally, we can add our own events under SamplleApp, each with its own event number.Event numbers are 16 bits, but only one of 16 bits is allowed per event number, which means a maximum of 16 events.

Let's first browse through the code, roughly to analyze the event number passed in and trigger the corresponding event.It feels like the task number processing mode.What we need to focus on is when the System Message Event is triggered.That is, the part after the if (events & SYS_EVENT_MSG) statement.First line:

  MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );

This line of code implements the ability to retrieve system message data.We can look at the definitions on our own.afIncomingMSGPacket is the type of structure that contains the entire message content.

The subsequent selection statements process the data accordingly based on the information in the message.We need to focus on the following code (Figure 8)

 

Figure 8

After half a day, it was still initializing... which means that when the network state changes (in fact, the network is open), the data is initialized for sending.Look at these three parameters, the first one is the task number, do not repeat.The second is the Event Number, which is also said, only one event per event!The third is to set the time, which is how often you send messages!Here we preset SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT = 5000, which can be modified by itself in milliseconds, which means the program sends data once in five seconds.

(2) Set up the sending content and send it automatically and periodically.The following code is found under the same function (Figure 9)

 

Figure 9

If the periodic data sending section is triggered (that is, five seconds have passed before the message is sent), execute the SampleApp_SendPeriodicMessage() function.This function is the focus. It contains the data we need to send.Continue to go to definition...

After finding the function, make the following modifications to the function (Figure 10).

 

Figure 10

Let's take a look at the function AF_DataRequest(), which tells us from the context that it must be the function that decides to send the data content.We need to focus on the third, fourth, and fifth parameters, which are used to establish contact with the recipient. Here we define SAMPLEAPP_PERIODIC_CLUSTERID=1. If the coordinator receives a packet and gets the label inside, it is a proof that the packet is coming in periodically.The fourth parameter represents the length of the data to be sent, and the fifth parameter is a pointer to the data to be sent.

The sending data section is over here~~

 

3. Receive partial code

Under SampleApp.c, find the function "void SampleApp_MessageMSGCB" (afIncomingMSGPacket_t *pkt), and add code in the line below "case SAMPLEAPP_PERIODIC_CLUSTERID:" (Figure 11):

HalUARTWrite(0, "I get data!\n", 12);

 HalUARTWrite(0, &pkt->cmd.Data[0], pkt->cmd.DataLength);

 HalUARTWrite(0, "\n", 1);

Figure 11

 

Instructions: Let's first look at the conditional statement "case SAMPLEAPP_PERIODIC_CLUSTERID:".This is the number that is set in the send section to represent periodic sending of data.Look, it's here to use ~

Where code is added, we can process the data we receive (not limited to serial sending).The three lines of code here are all sent by serial port, so don't say anything more.

Focus on "afIncomingMSGPacket_t *pkt".All data and information are in the afIncomingMSGPacket passed in by the function, see this definition

 1 typedef struct
 2 
 3 {
 4 
 5   osal_event_hdr_t hdr;     /* OSAL Message header */
 6 
 7   uint16 groupId;           /* Message's group ID - 0 if not set */
 8 
 9   uint16 clusterId;         /* Message's cluster ID */
10 
11   afAddrType_t srcAddr;     /* Source Address, if endpoint is STUBAPS_INTER_PAN_EP,
12 
13                                it's an InterPAN message */
14 
15   uint16 macDestAddr;       /* MAC header destination short address */
16 
17   uint8 endPoint;           /* destination endpoint */
18 
19   uint8 wasBroadcast;       /* TRUE if network destination was a broadcast address */
20 
21   uint8 LinkQuality;        /* The link quality of the received data frame */
22 
23   uint8 correlation;        /* The raw correlation value of the received data frame */
24 
25   int8  rssi;               /* The received RF power in units dBm */
26 
27   uint8 SecurityUse;        /* deprecated */
28 
29   uint32 timestamp;         /* receipt timestamp from MAC */
30 
31   uint8 nwkSeqNum;          /* network header frame sequence number */
32 
33   afMSGCommandFormat_t cmd; /* Application Data */
34 
35 } afIncomingMSGPacket_t;
afIncomingMSGPacket_t

It's a structure that contains the contents of the data package, so let's not mention it here. Want to know your own translation notes ~We'll focus on afMSGCommandFormat_t cmd.View its definition

typedef struct

{

  uint8   TransSeqNumber;

  uint16  DataLength;              // Number of bytes in TransData

  uint8  *Data;

} afMSGCommandFormat_t;
afMSGCommandFormat_t

Oh, here's the data we're sending!The DataLength is the length of the data, and the Data is the pointer to the data content.

Looking back, HalUARTWrite(0, &pkt->cmd.Data[0], pkt->cmd.DataLength); this code sends the received data to the serial port.

 

4. Program burning

Here's a note!Select mode when downloading!As shown in Figure 12, CoordinatorEB mode is loaded to the coordinator (the one connected to the computer!), EndDeviceEB mode to the terminal module!

Figure 12

The wireless data transfer experiment is over.

Didn't you remember?No problem!Here's a summary of the whole process.

    

6. Process Analysis

 

Figure 13

Does this flowchart make it easier to understand?

 

7. Serial port optimization

This recommendation goes to the basic Bluetooth slave usage method I wrote before

Address: http://www.cnblogs.com/Donut/p/4054348.html

Hee-hee Advertise yourself ~

The same way, except that the baud rate is 115200, and then the serial port connects to zigbee's UART0 (for this experiment only, then you define which serial port connects which one)

Posted by pgsjoe on Mon, 04 May 2020 17:09:56 -0700