if( xQueue != NULL ) { /* Start the two tasks as described in the comments at the top of this * file. */ xTaskCreate( prvQueueReceiveTask, /* The function that implements the task. */ "Rx", /* The text name assigned to the task - for debug only as it is not used by the kernel. */ configMINIMAL_STACK_SIZE, /* The size of the stack to allocate to the task. */ NULL, /* The parameter passed to the task - not used in this case. */ mainQUEUE_RECEIVE_TASK_PRIORITY, /* The priority assigned to the task. */ NULL ); /* The task handle is not required, so NULL is passed. */
/* Start the tasks and timer running. */ vTaskStartScheduler(); }
/* If all is well, the scheduler will now be running, and the following * line will never be reached. If the following line does execute, then * there was insufficient FreeRTOS heap memory available for the Idle and/or * timer tasks to be created. See the memory management section on the * FreeRTOS web site for more details on the FreeRTOS heap * http://www.freertos.org/a00111.html. */ for( ; ; ) { } }
#if ((configSUPPORT_STATIC_ALLOCATION == 1) && (configSUPPORT_DYNAMIC_ALLOCATION == 1)) uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the memory used by the queue was statically allocated to ensure no attempt is made to free the memory. */ #endif
typedefstructtskTaskControlBlock /* Theoldnamingconventionisusedtopreventbreakingkernelawaredebuggers. */ { volatile StackType_t * pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */
#if ( portUSING_MPU_WRAPPERS == 1 ) xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */ #endif
ListItem_t xStateListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */ ListItem_t xEventListItem; /*< Used to reference a task from an event list. */ UBaseType_t uxPriority; /*< The priority of the task. 0 is the lowest priority. */ StackType_t * pxStack; /*< Points to the start of the stack. */ char pcTaskName[ configMAX_TASK_NAME_LEN ]; /*< Descriptive name given to the task when created. Facilitates debugging only. *//*lint !e971 Unqualified char types are allowed for strings and single characters only. */
#if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) ) StackType_t * pxEndOfStack; /*< Points to the highest valid address for the stack. */ #endif
#if ( portCRITICAL_NESTING_IN_TCB == 1 ) UBaseType_t uxCriticalNesting; /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */ #endif
#if ( configUSE_TRACE_FACILITY == 1 ) UBaseType_t uxTCBNumber; /*< Stores a number that increments each time a TCB is created. It allows debuggers to determine when a task has been deleted and then recreated. */ UBaseType_t uxTaskNumber; /*< Stores a number specifically for use by third party trace code. */ #endif
#if ( configUSE_MUTEXES == 1 ) UBaseType_t uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */ UBaseType_t uxMutexesHeld; #endif
#if ( configGENERATE_RUN_TIME_STATS == 1 ) configRUN_TIME_COUNTER_TYPE ulRunTimeCounter; /*< Stores the amount of time the task has spent in the Running state. */ #endif
#if ( configUSE_NEWLIB_REENTRANT == 1 )
/* Allocate a Newlib reent structure that is specific to this task. * Note Newlib support has been included by popular demand, but is not * used by the FreeRTOS maintainers themselves. FreeRTOS is not * responsible for resulting newlib operation. User must be familiar with * newlib and must provide system-wide implementations of the necessary * stubs. Be warned that (at the time of writing) the current newlib design * implements a system-wide malloc() that must be provided with locks. * * See the third party link http://www.nadler.com/embedded/newlibAndFreeRTOS.html * for additional information. */ struct _reentxNewLib_reent; #endif
/* See the comments in FreeRTOS.h with the definition of * tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */ #if ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 !e9029 Macro has been consolidated for readability reasons. */ uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */ #endif
voidvTask1( void *pvParameters ) { constchar *pcTaskName = "Task 1 is running\r\n"; volatileuint32_t ul; /* volatile to ensure ul is not optimized away. */ /* As per most tasks, this task is implemented in an infinite loop. */ for( ;; ) { /* Print out the name of this task. */ vPrintString( pcTaskName ); /* Delay for a period. */ for( ul = 0; ul < mainDELAY_LOOP_COUNT; ul++ ) { /* This loop is just a very crude delay implementation. There is nothing to do in here. Later examples will replace this crude loop with a proper delay/sleep function. */ } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
voidvTask2( void *pvParameters ) { constchar *pcTaskName = "Task 2 is running\r\n"; volatileuint32_t ul; /* volatile to ensure ul is not optimized away. */ /* As per most tasks, this task is implemented in an infinite loop. */ for( ;; ) { /* Print out the name of this task. */ vPrintString( pcTaskName ); /* Delay for a period. */ for( ul = 0; ul < mainDELAY_LOOP_COUNT; ul++ ) { /* This loop is just a very crude delay implementation. There is nothing to do in here. Later examples will replace this crude loop with a proper delay/sleep function. */ } } }
intmain( void ) { /* Create one of the two tasks. Note that a real application should check the return value of the xTaskCreate() call to ensure the task was created successfully. */ xTaskCreate( vTask1, /* Pointer to the function that implements the task. */ "Task 1",/* Text name for the task. This is to facilitate debugging only. */ 1000, /* Stack depth - small microcontrollers will use much less stack than this. */ NULL, /* This example does not use the task parameter. */ 1, /* This task will run at priority 1. */ NULL ); /* This example does not use the task handle. */ /* Create the other task in exactly the same way and at the same priority. */ xTaskCreate( vTask2, "Task 2", 1000, NULL, 1, NULL ); /* Start the scheduler so the tasks start executing. */ vTaskStartScheduler();
/* If all is well then main() will never reach here as the scheduler will now be running the tasks. If main() does reach here then it is likely that there was insufficient heap memory available for the idle task to be created. Chapter 2 provides more information on heap memory management. */ for( ;; ); }
voidvTask1( void *pvParameters ) { constchar *pcTaskName = "Task 1 is running\r\n"; volatileuint32_t ul; /* volatile to ensure ul is not optimized away. */ /* If this task code is executing then the scheduler must already have been started. Create the other task before entering the infinite loop. */ xTaskCreate( vTask2, "Task 2", 1000, NULL, 1, NULL ); for( ;; ) { /* Print out the name of this task. */ vPrintString( pcTaskName ); /* Delay for a period. */ for( ul = 0; ul < mainDELAY_LOOP_COUNT; ul++ ) { /* This loop is just a very crude delay implementation. There is nothing to do in here. Later examples will replace this crude loop with a proper delay/sleep function. */ } } }
voidvTaskFunction( void *pvParameters ) { char *pcTaskName; volatileuint32_t ul; /* volatile to ensure ul is not optimized away. */ /* The string to print out is passed in via the parameter. Cast this to a character pointer. */ pcTaskName = ( char * ) pvParameters; /* As per most tasks, this task is implemented in an infinite loop. */ for( ;; ) { /* Print out the name of this task. */ vPrintString( pcTaskName ); /* Delay for a period. */ for( ul = 0; ul < mainDELAY_LOOP_COUNT; ul++ ) { /* This loop is just a very crude delay implementation. There is nothing to do in here. Later exercises will replace this crude loop with a proper delay/sleep function. */ } } }
/* Define the strings that will be passed in as the task parameters. These are defined const and not on the stack to ensure they remain valid when the tasks are executing. */ staticconstchar *pcTextForTask1 = "Task 1 is running\r\n"; staticconstchar *pcTextForTask2 = "Task 2 is running\r\n"; intmain( void ) { /* Create one of the two tasks. */ xTaskCreate( vTaskFunction, /* Pointer to the function that implements the task. */ "Task 1", /* Text name for the task. This is to facilitate debugging only. */ 1000, /* Stack depth - small microcontrollers will use much less stack than this. */ (void*)pcTextForTask1, /* Pass the text to be printed into the task using the task parameter. */ 1, /* This task will run at priority 1. */ NULL ); /* The task handle is not used in this example. */ /* Create the other task in exactly the same way. Note this time that multiple tasks are being created from the SAME task implementation (vTaskFunction). Only the value passed in the parameter is different. Two instances of the same task are being created. */ xTaskCreate( vTaskFunction, "Task 2", 1000, (void*)pcTextForTask2, 1, NULL ); /* Start the scheduler so the tasks start executing. */ vTaskStartScheduler();
/* If all is well then main() will never reach here as the scheduler will now be running the tasks. If main() does reach here then it is likely that there was insufficient heap memory available for the idle task to be created. Chapter 2 provides more information on heap memory management. */ for( ;; ); }
任务优先级
configMAX_PRIORITIES
configUSE_PORT_OPTIMISED_TASK_SELECTION
时间尺度和滴答中断
configTICK_RATE_HZ
100image-20230223094018410
pdMS_TO_TICKS()
Example 3. Experimenting with priorities
image-20230223094342546
扩展非运行状态
阻塞状态(Blocked)
暂停状态(Suspended)
就绪状态(Ready)
完整的状态切换图
image-20230223094909681
Example 4. Using the Blocked state to create a delay
用户与运行调试器(如gdb)的调试主机(如笔记本电脑)交互。调试器与调试转换器(例如OpenOCD,它可能包括一个硬件驱动程序)通信,以与调试传输硬件(例如Olimex USB-JTAG适配器)通信。调试传输硬件将调试主机连接到平台的调试传输模块(Debug Transport Module, DTM)。DTM使用调试模块接口(DMI)提供对一个或多个调试模块(dm)的访问。
/* * Task control block. A task control block (TCB) is allocated for each task, * and stores task state information, including a pointer to the task's context * (the task's run time environment, including register values) */ typedef struct tskTaskControlBlock /* The old naming convention is used to prevent breaking kernel aware debuggers. */ { volatile StackType_t * pxTopOfStack; /**< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */
ListItem_t xStateListItem; /**< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */ ListItem_t xEventListItem; /**< Used to reference a task from an event list. */ UBaseType_t uxPriority; /**< The priority of the task. 0 is the lowest priority. */ StackType_t * pxStack; /**< Points to the start of the stack. */ char pcTaskName[ configMAX_TASK_NAME_LEN ]; /**< Descriptive name given to the task when created. Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
UBaseType_t uxBasePriority; /**< The priority last assigned to the task - used by the priority inheritance mechanism. */ UBaseType_t uxMutexesHeld;
/* The old tskTCB name is maintained above then typedefed to the new TCB_t name * below to enable the use of older kernel aware debuggers. */ typedef tskTCB TCB_t;
动态创建任务
1 2 3 4 5 6 7
// tasks.c BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ const configSTACK_DEPTH_TYPE usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask )
OpenOCD configuration summary -------------------------------------------------- Linux GPIO bitbang through libgpiod no SEGGER J-Link Programmer yes (auto) Dummy Adapter yes RISC-V Link Adapter yes Use Capstone disassembly framework no
// struct adiv5_dap->adi_version struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct armv7a_common *armv7a = &cortex_a->armv7a_common; armv7a->debug_ap->dap->adi_version == 5; /** Indicates ADI version (5, 6 or 0 for unknown) being used */
// src/server/server.h struct connection { int fd; int fd_out; /* When using pipes we're writing to a different fd */ struct sockaddr_in sin; struct command_context *cmd_ctx; struct service *service; bool input_pending; void *priv; struct connection *next; };
$ ./src/openocd -s tcl -f tcl/interface/rvlink.cfg -f tcl/target/simu/nemu.cfg Open On-Chip Debugger 0.12.0+dev-03889-g5fefbc2da-dirty (2024-09-10-10:57) Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html Info : Connected to server 127.0.0.1:51234 Info : Listening on port 6666 for tcl connections Info : Listening on port 4444 for telnet connections Info : Note: The adapter "RV-LINK" doesn't support configurable speed Info : JTAG tap: nemu.cpu tap/device found: 0x3ba0184d (mfg: 0x426 (Google Inc), part: 0xba01, ver: 0x3) Info : [nemu.cpu] datacount=1 progbufsize=0 Warn : [nemu.cpu] We won't be able to execute fence instructions on this target. Memory may not always appear consistent. (progbufsize=0, impebreak=0) Info : [nemu.cpu] Vector support with vlenb=0 Info : [nemu.cpu] S?aia detected with IMSIC Info : [nemu.cpu] Core 0 made part of halt group 1. Info : [nemu.cpu] Examined RISC-V core Info : [nemu.cpu] XLEN=32, misa=0x40000000 [nemu.cpu] Target successfully examined. Info : [nemu.cpu] Examination succeed Info : [nemu.cpu] starting gdb server on 3333 Info : Listening on port 3333 for gdb connections
# 使用vexpress默认配置编译 cd linux-4.14.334 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- vexpress_defconfig make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- menuconfig # 开启NFS4支持。 # 位置:File System -> Network File Systems->NFS client support for NFS version 4 (相关的四项全勾上)
# 编译内核 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- zImage -j$(nproc) make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- LOADADDR=0x60003000 uImage -j$(nproc) make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- modules -j$(nproc) make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- dtbs -j$(nproc) cd ..
structbvec_iter { sector_t bi_sector; /* device address in 512byte sectors */ unsignedint bi_size; /* residual I/O count */ unsignedint bi_idx; /* current index into bvl_vec */ unsignedint bi_bvec_done; /* number of bytes completed in current bvec */ };
structbio { structbio *bi_next;/* request queue link */ structblock_device *bi_bdev; unsignedlong bi_flags; /* status, command, etc */ unsignedlong bi_rw; /* bottom bits READ/WRITE, * top bits priority */ structbvec_iterbi_iter; /* Number of segments in this BIO after * physical address coalescing is performed. */ unsignedint bi_phys_segments; ...
structbio_vec *bi_io_vec;/* the actual vec list */ structbio_set *bi_pool; /* * We can inline a number of vecs at the end of the bio, to avoid * double allocations for a small number of bio_vecs. This member * MUST obviously be kept at the very end of the bio. */ structbio_vecbi_inline_vecs[0]; };
$ ls -l /dev/vmem_disk* brw-rw---- 1 root disk 252, 0 2月 25 14:00 /dev/vmem_diska brw-rw---- 1 root disk 252, 16 2月 25 14:00 /dev/vmem_diskb brw-rw---- 1 root disk 252, 32 2月 25 14:00 /dev/vmem_diskc brw-rw---- 1 root disk 252, 48 2月 25 14:00 /dev/vmem_diskd
$ sudo mkfs.ext2 /dev/vmem_diska mke2fs 1.42.9 (4-Feb-2014) Filesystem label= OS type: Linux Block size=1024 (log=0) Fragment size=1024 (log=0) Stride=0 blocks, Stripe width=0blocks 64 inodes, 512 blocks 25 blocks (4.88%) reserved for the super user First data block=1 Maximum filesystem blocks=524288 1 block group 8192 blocks per group, 8192fragments per group 64 inodes per group Allocating group tables: done Writing inode tables: done Writing superblocks and filesystem accounting information: done