Introduction to BES SDK Software Architecture Development

Hello everyone! Last time I wrote a single-wire serial communication module based on Hengxuan module. This article will give a brief introduction to Hengxuan Bluetooth SDK.

1. Software system architecture

1. BES uses RXT RTOS (embedded real-time operating system), and uses ARM's CMSIS_RTOS API interface

2. We know that the place where the program starts is _main_init() in RTX_CM_LIB.H, which is mainly to initialize the kernel, set the stack, create the main thread, and start the kernel.

3. The first thread os_thread_def_main is main, and then look at it in the main.cpp file.

Then it is the initialization of the debug port (we use debug=1 for one hand) by default to enable the print output of UART0 RX.

After uart is initialized, it will print out the current software, chip, flash partition size and other information in hal_trace.c:

The printout is roughly as follows:

[18:35:14.391]CHIP=best1305
[18:35:14.391]KERNEL=RTX5
[18:35:14.391]CRASH_DUMP_SIZE=0
[18:35:14.391]AUD_SEC_SIZE=0x10000
[18:35:14.391]USER_SEC_SIZE=0x1000
[18:35:14.391]FACT_SEC_SIZE=0x1000
[18:35:14.391]NV_REC_DEV_VER=2
[18:35:14.391]FLASH_BASE=0x38000000
[18:35:14.391]FLASH_SIZE=0x400000
[18:35:14.391]OTA_CODE_OFFSET=0x28000
[18:35:14.391]CRC32_OF_IMAGE=0x00000000
[18:35:14.391]BUILD_DATE=Mar 10 2021 18:21:32
[18:35:14.391]REV_INFO=:best2500i_JBL_T230
[18:35:14.391]
[18:35:14.391]
[18:35:14.391]------
[18:35:14.391]METAL_ID: 0
[18:35:14.391]------

Then the software will run to determine whether the actual flash size matches the software definition. If the software-defined flash size exceeds the chip's built-in flash size, it will print out

“Wrong FLASH_SIZE defined in target.mk!”

“FLASH_SIZE is defined as 0x20000 while the actual chip flash size is 0x40000” 随后死机。

If there is no abnormality in the flash, the hardware IO configuration and analog input and output IO configuration will be started.

Then ran into app_init

Finally, if the initialization is completed, the thread task will be executed in an endless loop

 

If the initialization in app_init ends prematurely and returns non-zero, then shut down directly

 

4. BES thread/task message/timer creation and use.

Let me talk about a conceptual understanding first: 1. Thread is a task scheduling process based on RTOS (simulating multi-core occupancy time slice)

                                  2. Each thread is independent and will not be executed at the same time 

                                  3. A thread can contain multiple message module processing.

A. Thread

The first thread os_thread_def_main is main, then look at it, in the main.cpp file:

There is thread creation in app_os_init(). This is the style of CMSIS. If you have developed STM32, you should be familiar with it. It is used to define threads, timers and mailbox communications, etc.;
app_thread_tid = osThreadCreate(osThread(app_thread), NULL);

app_thread is the thread loop function, OSThread is actually a macro, just to take the address
#define osThread(name) &os_thread_def_##name

So OSThreadDef is to set the thread name, priority and stack size, get the pointer of the configured structure variable through osThread, and then pass it to OSThreadCreate() as a parameter.

Generally, you will see this definition at the beginning of the file: osThreadDef is actually a macro
osThreadDef(app_thread, osPriorityHigh, 1, 1024, “app_thread”);

PS: The early thread definition is like this:

/* thread */
static osThreadId uartrxtx_tid; 
uint32_t os_thread_def_stack_uartrxtx [UART_STACK_SIZE/ sizeof(uint32_t)];
osThreadDef_t os_thread_def_app_uartrxtx = {(app_uartrxtx),(osPriorityHigh),(UART_STACK_SIZE),(os_thread_def_stack_uartrxtx)};

Here is to initialize and assign a structure variable, and then pass the address of os_thread_def_app_thread to os_thread(). The structure type is:

/  ==== Thread Management Functions ====

/// Create a Thread Definition with function, priority, and stack requirements.
/// \param         name          name of the thread function.
/// \param         priority      initial priority of the thread function.
/// \param         instances     number of possible thread instances.
/// \param         stacksz       stack size (in bytes) requirements for the thread function.
/// \note CAN BE CHANGED: The parameters to \b osThreadDef shall be consistent but the
///       macro body is implementation specific in every CMSIS-RTOS.

#define osThreadDef(name, priority, instances, stacksz, task_name) \
uint64_t os_thread_def_stack_##name [(8*((stacksz+7)/8)) / sizeof(uint64_t)]; \
const osThreadDef_t os_thread_def_##name = \
{(name), \
  {task_name, osThreadDetached, NULL, 0U, os_thread_def_stack_##name, 8*((stacksz+7)/8), (priority), 1U, 0U}}
The following is about thread creation:

Let's look at the execution of the thread:

Let's take a look at what is done in the app_thread thread:
if (mod_handler[msg_p->mod_id])
int ret = mod_handler[msg_p->mod_id] (&(msg_p->msg_body));

We can see that in the app_thread thread, the mailbox information is repeatedly obtained through app_mailbox_get() and passed into mod_handler[].
static APP_MOD_HANDLER_T mod_handler[APP_MODUAL_NUM];
Insert picture description here
Look at its data type as an array of function pointers, and look at the definition of its array subscript:

The actual code connection used for thread creation is as follows (including the old and new versions):

https://share.weiyun.com/GUat9L7n

 

B: Message task:

The message task is based on the next level of processing of the thread 

At present, the general message task processing is based on the app_thread thread. Of course, task processing can also be added to the remaining threads.

From the above thread explanation, we know that each module will register its own callback function, and then app_thread() will process it according to the API corresponding to the get message callback module.

Therefore, the task needs to register the message execution function after app_os_init before registering.

 

General interface of message processing function:

The return value is int type data, which carries the structure parameter pointer of APP_MESSAGE_BOY *.

Here is an explanation of NTC message processing that I wrote:

C timer:

Timers are divided into software timers and hardware timers, which essentially execute interrupt processing when the time is up.

The difference is that the hardware timer is based on the hardware clock, so it is relatively more accurate and the measurement accuracy is smaller, and the hardware timer is one-time.

The timer can be reloaded but cannot be used in interrupts .

C1: hardware timer

Header file: #include "hwtimer_list.h"

static HWTIMER_ID app_box_det_debounce_tid = NULL; //Hardware timer ID definition is generally defined as all variables

app_box_det_debounce_tid = hwtimer_alloc(app_box_det_debounce_timehanlder, NULL); //Associated timer interrupt execution function. app_box_det_debounce_timehanlder will carry void* type parameters.

hwtimer_start(app_box_det_debounce_tid,MS_TO_TICKS(200));// To start the timer, please note that you can’t fill in the time directly later, it needs to be converted to a clock

hwtimer_stop(app_box_det_debounce_tid); // The timer can be stopped early, remove the queue and change the timer as it is no longer executed.

 

C2: Software timer:

head File:

#include "cmsis_os.h"
#include "hal_timer.h"

typedef enum {
  osTimerOnce               = 0,          ///< One-shot timer.
  osTimerPeriodic           = 1           ///< Repeating timer.
} osTimerType_t;

static osTimerId app_battery_timer = NULL; //Software timer ID  
static void app_battery_timer_handler(void const *param); //Timer interrupt execution function, can carry void* type parameters
osTimerDef (APP_BATTERY, app_battery_timer_handler); //Software timer needs to be used Macro associated timer and execution function

app_battery_timer = osTimerCreate (osTimer(APP_BATTERY), osTimerPeriodic, NULL); //software timer creation APP_BATTERY is the timer addressing ID 

The second parameter is whether the timer is periodic or not. If it is one-time, it will not be executed again after the time is up, but the ID can still be started again.

 osTimerStop(app_battery_timer); //Stop the software timer
 osTimerStart(app_battery_timer,5000); //Restart the software timer and execute the timer interrupt after 5S.

 

The system architecture of this article is here for the time being. Detailed analysis of the subsequent sub-modules. Please continue to subscribe to view, thank you!

QQ:1902026113

 

 

Guess you like

Origin blog.csdn.net/qq_34990604/article/details/114928487