4.3.2 Semaphore
Semaphores are used for synchronization and to control access to shared resources between tasks. A semaphore can either be binary or counting and is essentially just a non-negative integer count.
A binary semaphore is initialized to 1 and can be used to guard a
                  resource that can only be handled by one task at a time. When a task takes the
                  resource, the semaphore is decremented to 0. If another task then wants to use the
                  resource and sees that the semaphore is 0, it blocks. When the first task is
                  finished using the resource, the semaphore is incremented and is thus available to
                  other tasks. A binary semaphore can be created with SemaphoreHandle_t
                        semaphoreName = xSemaphoreCreateBinary(void).
A counting semaphore works in the same manner, but for resources that
                  can be used by multiple tasks at once. For example, if you have a parking garage
                  with room for 10 cars, you can allow 10 semaphore access. Every time a car enters,
                  the semaphore will be decremented by 1 until it reaches 0 and no one is allowed
                  entrance before someone leaves. A counting semaphore should be initialized to the
                  number of tasks that can have concurrent access to the resource and is created
                  with SemaphoreHandle_t semaphoreName = xSemaphoreCreateCounting(maxCount,
                        initialCount).
When a task wants a resource protected by a semaphore, it calls the
                  function xSemaphoreTake(semaphoreName, ticksToWait). If the
                  semaphore evaluates to 0, the task will block for the time specified in
                        ticksToWait. When a task is finished using the semaphore,
                  the function xSemaphoreGive(semaphoreName) is called.
