1. Preface
In embedded operating system, the two-valued signal is an important means to synchronize between tasks and interrupts. FreeRTOS's two-value signal is easy to use, with a specific example below to illustrate how the two-value semaphore in FreeRTOS is used."Related blog posts""FreeRTOS STM32 Transplant Notes""FreeRTOS Learning Notes – Using queues to synchronize data between Tasks" "How to implement low power--msp430f5438 platform under freertos" "Code Link"--sample code stored in Baidu network disk
2. Special Instructions The method of using the binary semaphore is shown in Figure 1, which can be understood as a sign between a task and a break or between two tasks, which is not "full" or "empty". The send operation quite puts the flag "full", and the receive operation is related to "empty" the flag, and the send and receive operations synchronize tasks with interrupts or between two tasks.
Figure 12 Value-based semaphore usage
"Special Instructions" V7. There is a slight difference between the X version and the semaphore operation of the v8.x V7. Used in version XThe vsemaphorecreatebinary function, which uses the function to create a semaphore with an initial value of "full", returns the receive operation immediately. Related code see the article at the end of the supplementary Code 1, from the supplementary Code 1 can be found that the semaphore is created immediately after the call to the xsemaphoregive function, so that the semaphore from "empty" to "full". V8. The Xsemaphorecreatebinary function is used in the X version to create a semaphore with an initial value of "null", and the receive operation does not return immediately.
3. Reference CodeThe sample code has a 128-byte serial receive buffer, in the serial interrupt to the received characters in the buffer, once the carriage return to the line (\ r \ n), the signal by XSEMAPHOREGIVEFROMISR the volume "full", Use Xsemaphoretake in the print task to synchronize the interrupt receive function.Xsemaphoretake The task hangs, once the query to the semaphore is "full", through the serial port to print the end to the content, and empty the buffer. "Sample Code"
/* Standard includes. */#include <stdio.h> #include <string.h>/* Scheduler includes. */#include "FreeRTOS.h" #include "task.h" #include "queue.h" #include "semphr.h"/* Library includes. */#include "stm32f10x.h" #define LED0_ON () gpio_setbits (gpiob,gpio_pin_5); #define Led0_off () gpio_resetbits (GPIOB, gpio_pin_5), static void Setup (void), static void Printtask (void *pvparameters), void Ledinit (void), void uart1init (void) ; uint8_t rxbuffer[128];__io uint8_t rxcounter = 0; semaphorehandle_t Xsemaphore;int Main (void) {/* Initialize hardware platform */Setup (); /* Create semaphore */Xsemaphore = Xsemaphorecreatebinary (); /* Create print Task */xtaskcreate (Printtask, "Print task", configminimal_stack_size, NULL, tskidle_priority+4, NULL); /* Start OS */Vtaskstartscheduler (); return 0;} void Printtask (void *pvparameters) {for (;;) {if (Xsemaphoretake (Xsemaphore, portmax_delay) = = pdtrue) {printf ("receive:%s", Rxbuffer); memset (Rxbuffer, 0x00, 128); Rxcounter = 0; }}}static void Setup (void) {ledinit (); Uart1init ();} void Ledinit (void) {gpio_inittypedef gpio_initstructure; Rcc_apb2periphclockcmd (Rcc_apb2periph_gpiob, ENABLE); /*led0 @ gpiob.5*/gpio_initstructure.gpio_pin = gpio_pin_5; Gpio_initstructure.gpio_speed = Gpio_speed_50mhz; Gpio_initstructure.gpio_mode = gpio_mode_out_pp; Gpio_init (Gpiob, &gpio_initstructure); }void uart1init (void) {gpio_inittypedef gpio_initstructure; Usart_inittypedef usart_initstructure; /* 1th step: Open Gpio and Usart clock */rcc_apb2periphclockcmd (Rcc_apb2periph_gpioa | Rcc_apb2periph_usart1, ENABLE); /* 2nd step: Configure the GPIO for USART1 [email protected] as push-pull multiplexing mode */Gpio_initstructure.gpio_pin = Gpio_pin_9; Gpio_initstructure.gpio_mode = gpio_mode_af_pp; Gpio_initstructure.gpio_speed = Gpio_speed_50mhz; Gpio_init (Gpioa, &gpio_initstructure); /* Step 3rd: Configure the GPIO for USART1 [email protected] to float input mode */GPIO_INITSTRUCTURE.GPIo_pin = gpio_pin_10; Gpio_initstructure.gpio_mode = gpio_mode_in_floating; Gpio_init (Gpioa, &gpio_initstructure); Gpio_initstructure.gpio_speed = Gpio_speed_50mhz; Gpio_init (Gpioa, &gpio_initstructure); /* 4th step: Configure the USART1 parameter baud rate = 9600 data length = 8 stop bit = 1 Check bit = no disables hardware flow control (that is, RTS and CTS are forbidden) enable receive and send */usart_i Nitstructure.usart_baudrate = 9600; Usart_initstructure.usart_wordlength = usart_wordlength_8b; Usart_initstructure.usart_stopbits = Usart_stopbits_1; usart_initstructure.usart_parity = Usart_parity_no; Usart_initstructure.usart_hardwareflowcontrol = Usart_hardwareflowcontrol_none; Usart_initstructure.usart_mode = Usart_mode_rx | Usart_mode_tx; Usart_init (USART1, &usart_initstructure); /* 5th step: Enable USART1, Configuration complete */Usart_cmd (USART1, enable); /* Clear Send Completion flag */Usart_clearflag (USART1, USART_FLAG_TC); /* Enable USART1 to send interrupts and receive interrupts, and set priority */Nvic_inittypedef nvic_initstructure; /* Set USART1 Interrupt priority */NVIC_initstructure.nvic_irqchannel = USART1_IRQN; nvic_initstructure.nvic_irqchannelpreemptionpriority = configlibrary_kernel_interrupt_priority; nvic_initstructure.nvic_irqchannelsubpriority = 0; Nvic_initstructure.nvic_irqchannelcmd = ENABLE; Nvic_init (&nvic_initstructure); /* Enable receive interrupt */Usart_itconfig (USART1, Usart_it_rxne, enable); }int FPUTC (int ch, FILE *f) {/* Write a byte to USART1 */Usart_senddata (USART1, (uint8_t) ch); /* Wait for Send end */while (Usart_getflagstatus (USART1, usart_flag_txe) = = RESET) {} return ch;} void Usart1_irqhandler (void) {static basetype_t xhigherprioritytaskwoken; if (Usart_getitstatus (USART1, usart_it_rxne)! = RESET) {rxbuffer[rxcounter++] = Usart_receivedata (USART1); if (Rxcounter > 2 && rxbuffer[rxcounter-2] = = ' \ r ' && rxbuffer[rxcounter-1] = = ' \ n ') {// Send Semaphore Xsemaphoregivefromisr in interrupt (Xsemaphore, &xhigherprioritytaskwoken); }} Portyield_froM_ISR (Xhigherprioritytaskwoken);}
4. Brief descriptionsemaphorehandle_t Xsemaphore;Semaphore handle, binary semaphore, numeric semaphore, and mutex signal are all usedsemaphorehandle_t Type declarationXsemaphore = Xsemaphorecreatebinary ();Create a semaphore, add a new function to the v8.x version, and create a semaphore with an initial value of "null". Xsemaphoregivefromisr (Xsemaphore, &xhigherprioritytaskwoken);When sending semaphores in interrupts, the function with the end of FROMISR has the protection function, if the semaphore is sent in the task can use xsemaphoregive. Xsemaphoretake (Xsemaphore, portmax_delay);Wait for the semaphore, the wait time is the maximum wait time, if the semaphore is "empty" the task will be in the suspended state.
5. Use the RTOs API to note points in interrupts"Fromisr" should use XSEMAPHOREGIVEFROMISR instead ofxsemaphoregive. "Interrupt priority setting" the serial interrupt priority should be lower than configmax_syscall_interrupt_priority (191, from another angle can be understood as 11) set the highest priority, The response priority of the UART in this article is configlibrary_kernel_interrupt_priority (the macro has a value of 15, the higher the value, the lower the priority). "Main.c"/* Enable USART1 to send interrupts and receive interrupts, and set priority */nvic_inittypedef nvic_initstructure;/ * Set USART1 Interrupt priority * /nvic_initstructure.nvic_irqchannel = usart1_irqn;nvic_initstructure.nvic_irqchannelpreemptionpriority = configlibrary_kernel_interrupt_priority;nvic_initstructure.nvic_irqchannelsubpriority = 0;nvic_initstructure.nvic_irqchannelcmd = ENABLE;Nvic_init (&nvic_initstructure);
"FreeRTOSConfig.h"/* This is the raw value as per the cortex-m3 NVIC. Values can be 255(lowest) to 0 (1?) (highest). */#define CONFIGKERNEL_INTERRUPT_PRIORITY 255#define CONFIGMAX_SYSCALL_INTERRUPT_PRIORITY 191/* equivalent to 0xb0, or priority one. * //* This is the value being used as per the ST library which permitsPriority values, 0 to 15. This must correspond to theconfigkernel_interrupt_priority setting. Here's corresponds to the lowestNVIC value of 255. * *#define Configlibrary_kernel_interrupt_priority
In view of the characteristics of the cortex M3 Nvic, please refer to "Running M3 on Cortex freertos platform" for details.
5. Summary"1" V8. Used in Xxsemaphorecreatebinary ()The semaphore was created with an initial value of "null". the "2" interrupt sends the semaphore as far as possible using XXXXFROMISR. "3" the priority value of an interrupt should be greater than configmax_syscall_interrupt_priority.
"Supplemental Code 1"--vsemaphorecreatebinary function implementation code
#define Vsemaphorecreatebinary (Xsemaphore) { (Xsemaphore) = Xqueuegenericcreate ((unsigned portbase_type) 1, Semsemaphore_queue_item_length, Queuequeue_type_binary_semaphore); if ((xsemaphore) = NULL) { (void) xsemaphoregive ((Xsemaphore)); } }
6. References【STM32 and FreeRTOS study memo, XSEMAPHOREGIVEFROMISR "
FreeRTOS Study notes-two-value signal volume