TIM6 and TIM7 slotted non-blocking delays

An array that offers “slots” for the non-blocking delays you need in your program. Before including the header of one of these two libraries, you have to define the size of the array that means, the number of the delays you need. TIM6 or TIM7 are used as counters at a frequency also defined by the user. Then you insert numbers in the cells of the array, representing the time you want to pass, at the frequency defined by you. You can have the TIM counter overflowing at every one millisecond, and if you need a 500ms non-blocking delay, you insert that value in one of the array cells. At every millisecond, the library will scan the array and decrement by one all the values that are bigger than zero. Of course, the delays are not accurate, but allows you to have simultaneous, timed processes, simulating an RTOS system.

Requirements

It requires from the user to define the frequency and the size of the array that represents the number of required delays, before including the header of the library in his application. Like this:

#define TIM6_SNBD_FREQ 1000  // every 1 millisecond
#define TIM6_SNBD_NR_SLOTS 4 // we are using 4 different delays
#include "tim6_slotted_nb_delays.h"

Another requirement is to include the TIM SPL drivers into the project to have a successful compilation. But how it is constructed, the library does not need a configuration from within VPC like bellow:

So, in that case, if you don’t need any other TIMER and none is configured via VPC, the VPC will not include the headers needed for the timer peripheral, stm32l1xx_tim.h and stm32l1xx_tim.c respectively, leading the user to make manual interventions in the Makefile. And that is exactly what I wanted to avoid.

As you know if you studied the VPC sources, some SPL drivers are included by default, but the inclusion of others is triggered when you configure that peripheral from VPC interface. And that was the case also for the TIMx peripherals. So I had to include those, tim header and it’s source in the list of the headers included by default:

So, there is simplification for the user/beginner sake. An example project will be provided in the next article (the example and the libraries are already in repository). Here is the library code (well, WordPress is replacing charactersd an it should not happen inside the code syntax highlighting – anyway, if you need the code, go to repository):

/*
 * Slotted, non-blocking delays
 * 
 * Concept taken from timer0 isr interval jal library, copyright (C) 2008 Joep Suijs
 * Ported by Vasile Guta-Ciucur in 2019 for the VPC project.
 * 
 * REQUIRES VPC version 3.3.3 or newer
 * 
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 
  associated documentation files (the "Software"), to deal in the Software without restriction,
  including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
  and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do
  so, subject to the following conditions:
 
  The above copyright notice and this permission notice shall be included in all copies or substantial
  portions of the Software.
 
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
 */

#ifndef TIM6_SLOTTED_NB_DELAYS_H_
#define TIM6_SLOTTED_NB_DELAYS_H_

#ifndef TIM6_SNBD_FREQ
#define TIM6_SNBD_FREQ 1000
#endif

#ifndef TIM6_SNBD_NR_SLOTS
#define TIM6_SNBD_NR_SLOTS 1
#endif
#include <stdint.h>
#include "typedefs.h"

uint16_t TIM6_SNBD_SLOTS[TIM6_SNBD_NR_SLOTS];

uint8_t tim6_snbd_check(uint8_t slot){
  if (TIM6_SNBD_SLOTS[slot] == 0) return TRUE;
  else return FALSE;
}

void tim6_snbd_set(uint16_t slot, uint16_t value){
  if(slot < TIM6_SNBD_NR_SLOTS) {
    __asm("cpsid i");
    TIM6_SNBD_SLOTS[slot] = value;
    __asm("cpsie i");
  }
}

void tim6_snbd_init(void){
  int16_t i;

  TIM_TimeBaseInitTypeDef TIM_InitStruct;
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
  
  TIM_InitStruct.TIM_Prescaler = (APB1_T_VALUE / TIM6_SNBD_FREQ / 10) - 1;
  TIM_InitStruct.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_InitStruct.TIM_Period = 9;
  TIM_InitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
  TIM_TimeBaseInit(TIM6, &TIM_InitStruct);
  TIM_Cmd(TIM6, ENABLE);
  
  TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update);
  TIM_SelectMasterSlaveMode(TIM6, TIM_MasterSlaveMode_Disable);
  
  TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE);
  TIM_SetCounter(TIM6, 0);
  TIM_GenerateEvent(TIM6, TIM_EventSource_Update);
  NVIC_EnableIRQ(TIM6_IRQn);

  for(i=0;i<TIM6_SNBD_NR_SLOTS;i++)
    TIM6_SNBD_SLOTS[i] = 0;
}

void TIM6_IRQHandler(void)
{
  uint16_t i;
  if (TIM_GetFlagStatus(TIM6, TIM_FLAG_Update) == 1){
    for(i=0;i<TIM6_SNBD_NR_SLOTS;i++)
      if(TIM6_SNBD_SLOTS[i] > 0) TIM6_SNBD_SLOTS[i] = TIM6_SNBD_SLOTS[i] - 1;
    TIM_ClearFlag(TIM6, TIM_FLAG_Update);
  }
}
    
#endif //TIM6_SLOTTED_NB_DELAYS_H_

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.