做业地址:
https://github.com/HustWolfzzb/STM32F429_Discovery_FreeRTOS_9
Git/GCC/GDB/QEMU等工具的使用。
FreeRTOS多任务同步和通讯机制的掌握。git
在github上,Fork例程项目(https://github.com/cbhust/STM32F429_Discovery_FreeRTOS_9.git) 到本身的我的帐号。
clone项目到本地电脑的Ubuntu虚拟机中(虚拟机环境在第一次做业中已搭建)。
按照/Projects/Demo1/README.md中的提示编译Demo1例程并经过Qemu运行例程。
在Demo1的框架基础上完成本身的本次编程做业(具体要求见第3点)。
代码完成后提交到本身的github帐号上,确保助教能够正常的clone并编译运行。
在做业博客上给出代码的github连接、代码说明以及运行结果展现。github
建立三个任务:Sender_Task,Receiver_Task, Monitor_Taskweb
说明:编程
说明:ubuntu
说明:建立一个新的队列。为新的队列分配所需的存储内存,并返回一个队列处理。
注意:项目经过复制而不是引用排队,所以,所需的字节数,将复制给每一个项目。队列中每一个项目必须分配一样大小。
返回:若是队列成功建立,则返回一个新建队列的处理。若是不能建立队列,将返回0。api
说明:这个与xQueueSend 是同样的,参照xQueueSend 的用法bash
说明:这个项目经过复制接收,所以缓冲器必须提供足够大的空间。这个函数必定不能在中断服务程序中使用当队列空时,确定复制传递不成功,则等待xTicksToWait 个滴答周期后再复制,但若是xTicksToWait 设置为0,调用将当即返回。
返回:若是项目成功被队列接收为pdTRUE ,不然为 pdFALSE。app
~~ ~~ ~~~~~ ~~~~~~~
# 做业过程(多图预警)
~ ~~~ ~~ ~~ ~~ ~~~~ ~框架
本例程使用qemu-system-gnuarmeclipse,该qemu分支对stm32f4有更好的支持,主要面向Eclipse开发环境,本文档给出在Ubuntu 16.04命令行环境下单独使用的方式。eclipse
#cd ~/work #tar xvf gnuarmeclipse-qemu-debian64-2.8.0-201612271623-dev.tgz #chmod -R -w ./qemu export PATH=~/work/qemu/2.8.0-201612271623-dev/bin/:$PATH
#qemu-system-gnuarmeclipse --version
如正常则会显示版本信息为2.8.0。
说明:qemu-system-gnuarmeclipse当前版本不支持STM32F4的浮点,相应的,FreeRTOS使用的portable目录没有使用ARM_CM4F而是使用ARM_CM3。
在Demo1目录下提供了一个qemu.sh脚本文件,内容以下:
#!/bin/bash qemu-system-gnuarmeclipse --verbose --verbose --board STM32F429I-Discovery --mcu STM32F429ZI -d unimp,guest_errors --image hello_rtos.elf --semihosting-config enable
在Demo1目录下运行脚本文件:
#./qemu.sh
则qemu开始执行hello_rtos.elf文件,在弹出的GUI中看到程序执行的效果。
Ubuntu缺省安装中没有gdb-arm-none-eabi工具,须要先安装
#sudo apt-get install gdb-arm-none-eabi
在Demo1目录下运行qemu_gdb脚本文件,该文件中添加了--gdb tcp::1234 -S
qemu启动后等待来自gdb的调试指令,打开另一个终端窗口,运行
#arm-none-eabi-gdb
在gdb界面内运行:
(gdb)target remote localhost:1234 (gdb)continue
能够看到qemu开始执行程序,GUI界面上能够看到程序执行效果。
## 5. Trace(略)
本例程启动了FreeRTOS的trace功能。
我采用了Mac编程,而后经过git的方式同步到ubuntu,不只锻炼了团队写做的神器--“Git”的使用技巧,同时也优化了本身的编程环境
说一下个人思路:
首先,采用全局变量来统领发送的数据和接收到的数据,经过在main函数外声明了一个发送数据的和,一个接收数据的和,一个队列用于传递因为周期不对等的发送和接受的数据。而后Sender_Task用于2ms发送一个数据,从1-10000循环,Receiver_Task 用于1000ms接收一波数据,大概是500个左右,因此队列的大小我定为510 ,虽然有不小的浪费,可是至少不会数据溢出。最后的Monitor_Task用于断定是否争取的发送和接受,因此这个时候就要用到两个全局变量,在10000ms的周期内断定一次是否两个数据和相等,若是发送的数据之和等于接受的数据之和,那么就毫无疑问的,发送没有问题。并且因为我规定,优先级上,Monitor>Receiver>Sender ,因此能够保证不会发生数据竞争致使的错漏。若是正确,那就亮绿灯,错误就是红灯,事实显示,一直是正确的!!
/** ****************************************************************************** * @file IO_Toggle/main.c * @author MCD Application Team * @version V1.0.0 * @date 19-September-2011 * @brief Main program body ****************************************************************************** * @attention * * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. * * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2> ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "stm32f429i_discovery.h" #include "stm32f4xx_gpio.h" #include "stm32f4xx_rcc.h" /* Kernel includes. */ #include "FreeRTOS.h" #include "task.h" #include "timers.h" #include "queue.h" /** @addtogroup STM32F4_Discovery_Peripheral_Examples * @{ */ /** @addtogroup IO_Toggle * @{ */ /* Private typedef -----------------------------------------------------------*/ GPIO_InitTypeDef GPIO_InitStructure; /* Private define ------------------------------------------------------------*/ /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ /* Private function prototypes -----------------------------------------------*/ /* Private functions ---------------------------------------------------------*/ void Hardware_Init(void); void Red_LED_On(void); void Red_LED_Off(void); void Green_LED_On(void); void Green_LED_Off(void); void ToggleLED1_Task(void*); void ToggleLED2_Task(void*); /** * @brief Main program * @param None * @retval None */ //张照博本身写的--START int32_t Send_Sum=0; int32_t Received_Sum=0; //创建队列 xQueueHandle MyQueue; void Sender_Task(void *pvParameters) { int32_t Send_Num = 1; for( ;; ) { vTaskDelay( 2 / portTICK_RATE_MS ); if (Send_Num>10000) { Send_Num=1; } /* 向队列中填充内容 */ xQueueSendToBack( MyQueue, ( void* )&Send_Num, 0 ); *((int32_t*)pvParameters)+=Send_Sum; Send_Num++; } } void Receiver_Task(void *pvParameters) { int32_t Received_Num = 0; for( ;; ) { /* 从队列中获取内容 */ if( xQueueReceive( MyQueue, &Received_Num, 1000 / portTICK_RATE_MS ) == pdTRUE) { *((int32_t*)pvParameters)+=Received_Num; Received_Num=*((int32_t*)pvParameters); } } } void Monitor_Task(void *pvParameters) { vTaskDelay( 10000 / portTICK_RATE_MS ); if(Send_Sum-Received_Sum<5 && Send_Sum-Received_Sum>-5) { Green_LED_On(); Red_LED_Off(); Send_Sum=0; Received_Sum=0; } else { Green_LED_Off(); Red_LED_On(); Send_Sum=0; Received_Sum=0; } } //张照博本身写的--END int main(void) { /*!< At this stage the microcontroller clock setting is already configured, this is done through SystemInit() function which is called from startup file (startup_stm32f4xx.s) before to branch to application main. To reconfigure the default setting of SystemInit() function, refer to system_stm32f4xx.c file */ Hardware_Init(); // 初始化硬件平台 //prvSetupHardware(); //建立全局变量 MyQueue = xQueueCreate( 510 , sizeof( int32_t ) ); // 创建任务 xTaskCreate( Sender_Task, ( signed portCHAR * ) "Sender_Task", configMINIMAL_STACK_SIZE,(void*)&Send_Sum, tskIDLE_PRIORITY+3, NULL ); xTaskCreate( Receiver_Task, ( signed portCHAR * ) "Receiver_Task", configMINIMAL_STACK_SIZE,(void*)&Received_Sum, tskIDLE_PRIORITY+4, NULL ); xTaskCreate( Monitor_Task, ( signed portCHAR * ) "Monitor_Task", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+5, NULL ); //启动OS vTaskStartScheduler(); return 0; //个人第一次调试,须要去掉后面的 /* Init and start tracing*/ vTraceEnable(TRC_INIT); vTraceEnable(TRC_START); // /* Create tasks */ // xTaskCreate( // ToggleLED1_Task, /* Function pointer */ // "Task_LED1", /* Task name - for debugging only*/ // configMINIMAL_STACK_SIZE, /* Stack depth in words */ // (void*) NULL, /* Pointer to tasks arguments (parameter) */ // tskIDLE_PRIORITY + 3UL, /* Task priority*/ // NULL /* Task handle */ // ); // xTaskCreate( // ToggleLED2_Task, /* Function pointer */ // "Task_LED2", Task name - for debugging only // configMINIMAL_STACK_SIZE, /* Stack depth in words */ // (void*) NULL, /* Pointer to tasks arguments (parameter) */ // tskIDLE_PRIORITY + 2UL, /* Task priority*/ // NULL /* Task handle */ // ); // /* Start the scheduler. */ // 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. */ // for( ;; ); //个人第一次调试,去掉的位置结尾 } /** * Hardware_Init: */ void Hardware_Init(void) { /* GPIOG Periph clock enable */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE); /* Configure PG13, PG14 in output pushpull mode */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13| GPIO_Pin_14; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOG, &GPIO_InitStructure); } /** * Red_LED_On: */ void Red_LED_On(void) { // GPIO_SetBits(GPIOG, GPIO_Pin_14); GPIOG->ODR |= 0x4000; } /** * Red_LED_Off: */ void Red_LED_Off(void) { // GPIO_ResetBits(GPIOG, GPIO_Pin_14); GPIOG->ODR &= 0xBFFF; } /** * Green_LED_On: */ void Green_LED_On(void) { // GPIO_SetBits(GPIOG, GPIO_Pin_13); GPIOG->ODR |= 0x2000; } /** * Green_LED_Off: */ void Green_LED_Off(void) { // GPIO_ResetBits(GPIOG, GPIO_Pin_13); GPIOG->ODR &= 0xDFFF; } /** * ToggleLED1_Task: Toggle LED1 via RTOS Timer */ void ToggleLED1_Task(void *pvParameters) { int led = 0; while (1) { if(led == 0) { Red_LED_On(); led = 1; } else { Red_LED_Off(); led = 0; } /* Delay for a period of time. vTaskDelay() places the task into the Blocked state until the period has expired. The delay period is spacified in 'ticks'. We can convert yhis in milisecond with the constant portTICK_RATE_MS. */ vTaskDelay(1000 / portTICK_RATE_MS); } } /** * ToggleLED2_Task: Toggle LED2 via RTOS Timer */ void ToggleLED2_Task(void *pvParameters) { int led = 0; while (1) { if(led == 0) { Green_LED_On(); led = 1; } else { Green_LED_Off(); led = 0; } /* Delay for a period of time. vTaskDelay() places the task into the Blocked state until the period has expired. The delay period is spacified in 'ticks'. We can convert yhis in milisecond with the constant portTICK_RATE_MS. */ vTaskDelay(2000 / portTICK_RATE_MS); } } void vApplicationTickHook( void ) { } /*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/ void vApplicationMallocFailedHook( void ) { /* vApplicationMallocFailedHook() will only be called if configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h. It is a hook function that will get called if a call to pvPortMalloc() fails. pvPortMalloc() is called internally by the kernel whenever a task, queue, timer or semaphore is created. It is also called by various parts of the demo application. If heap_1.c or heap_2.c are used, then the size of the heap available to pvPortMalloc() is defined by configTOTAL_HEAP_SIZE in FreeRTOSConfig.h, and the xPortGetFreeHeapSize() API function can be used to query the size of free heap space that remains (although it does not provide information on how the remaining heap might be fragmented). */ taskDISABLE_INTERRUPTS(); for( ;; ); } /*-----------------------------------------------------------*/ void vApplicationIdleHook( void ) { /* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set to 1 in FreeRTOSConfig.h. It will be called on each iteration of the idle task. It is essential that code added to this hook function never attempts to block in any way (for example, call xQueueReceive() with a block time specified, or call vTaskDelay()). If the application makes use of the vTaskDelete() API function (as this demo application does) then it is also important that vApplicationIdleHook() is permitted to return to its calling function, because it is the responsibility of the idle task to clean up memory allocated by the kernel to any task that has since been deleted. */ } /*-----------------------------------------------------------*/ void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName ) { ( void ) pcTaskName; ( void ) pxTask; /* Run time stack overflow checking is performed if configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook function is called if a stack overflow is detected. */ taskDISABLE_INTERRUPTS(); for( ;; ); } /*-----------------------------------------------------------*/ #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t* file, uint32_t line) { /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* Infinite loop */ while (1) { } } #endif /** * @} */ /** * @} */ /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/