# exact delay cycles in freeRTOS task

**URL:** <https://forums.freertos.org/t/exact-delay-cycles-in-freertos-task/1837>\
**Category:** Kernel\
**Created:** [June 12, 2014, 6:17pm UTC](https://forums.freertos.org/t/exact-delay-cycles-in-freertos-task/1837 "2014-06-12T18:17:34Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![system](https://d2v6vdsk2p900z.cloudfront.net/original/1X/7fc8fdb729c645aab5b20282bbe34e57cb407be6.jpeg) [@system](https://forums.freertos.org/u/system)\
**Post date:** [June 12, 2014, 6:17pm UTC](https://forums.freertos.org/t/exact-delay-cycles-in-freertos-task/1837/1 "2014-06-12T18:17:34Z")

</div>

**[jradoslav](https://sourceforge.net/u/jradoslav/)** wrote on [Thursday, June 12, 2014](https://sourceforge.net/p/freertos/discussion/382005/thread/52c7e56b/#7a0e):

Hi All

I have implemented task with software USART receiver where is call USART\_bit\_delay routine.  
This routine is implemented with delay\_us OR delay\_ns based on delay\_cycles(count)  
delay have to be exact tick count but these routine consumes task running state time.

```auto
void readByte()
{
    uses 8x bit delay function delay_cycles in ASF framework,
    how can be implemented in FreeRtos delay alternative?
}
void task()
{
   
    while(1)
    { 
         readByte(); // function consume running state and other tasks are blocked
    }
        
}

```

how can i implement next:

block task  
BitDelay  
unblock task

or

freertosBitDelay()

thank you

---

<div class="post-metadata">

**Author:** ![system](https://d2v6vdsk2p900z.cloudfront.net/original/1X/7fc8fdb729c645aab5b20282bbe34e57cb407be6.jpeg) [@system](https://forums.freertos.org/u/system)\
**Post date:** [June 12, 2014, 7:03pm UTC](https://forums.freertos.org/t/exact-delay-cycles-in-freertos-task/1837/2 "2014-06-12T19:03:36Z")

</div>

**[bowerymarc](https://sourceforge.net/u/bowerymarc/)** wrote on [Thursday, June 12, 2014](https://sourceforge.net/p/freertos/discussion/382005/thread/52c7e56b/#7a0e/144f):

Looks like you’re using bit delay for sampling, so they have to be pretty precise, and I’m guessing pretty fast, much faster than 1mS. I’d suggest using a timer with an interrupt, set the timer to the sample period you want, and grab the bit there.  
Keep some static variables so when you accumulate a byte, you could push it into a queue and use the queue as your blocking mechanism.

On Jun 12, 2014, at 2:17 PMEDT, Radoslav Jízdný [jradoslav@users.sf.net](mailto:jradoslav@users.sf.net) wrote:

> Hi All
> 
> I have implemented task with software USART receiver where is call USART\_bit\_delay routine.  
> This routine is implemented with delay\_us OR delay\_ns based on delay\_cycles(count)  
> delay have to be exact tick count but these routine consumes task running state time.
> 
> void readByte()  
> {  
> uses 8x bit delay function delay\_cycles in ASF framework,  
> how can be implemented in FreeRtos delay alternative?  
> }  
> void task()  
> {
> 
> ```
> while(1)
> { 
> readByte(); // function consume running state and other tasks are blocked
> }
> 
> ```
> 
> }  
> how can i implement next:
> 
> block task  
> BitDelay  
> unblock task
> 
> or
> 
> freertosBitDelay()
> 
> thank you
> 
> exact delay cycles in freeRTOS task
> 
> Sent from [sourceforge.net](http://sourceforge.net) because you indicated interest in [SourceForge.net: Log In to SourceForge.net](https://sourceforge.net/p/freertos/discussion/382005/)
> 
> To unsubscribe from further messages, please visit [SourceForge.net: Log In to SourceForge.net](https://sourceforge.net/auth/subscriptions/)

---

<div class="post-metadata">

**Author:** ![htibosch](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/htibosch/32/62_2.png) [@htibosch](https://forums.freertos.org/u/htibosch)\
**Post date:** [June 12, 2014, 7:59pm UTC](https://forums.freertos.org/t/exact-delay-cycles-in-freertos-task/1837/3 "2014-06-12T19:59:45Z")

</div>

**[heinbali01](https://sourceforge.net/u/heinbali01/)** wrote on [Thursday, June 12, 2014](https://sourceforge.net/p/freertos/discussion/382005/thread/52c7e56b/#64ee):

Hi Radoslav,

Yes same idea: install a timer interrupt, which takes RX samples at fixed intervals.  
If the baudrate is 9600, the interrupt rate should be 3 to 5 times faster: 28.8 or 48 Khz.

If you want to make your timer interrupt ‘lighter’, you could put the samples in a circular buffer with a head and a tail pointer: the head for writing samples (from the interrupt) and the tail for reading them (from your task).

And as soon as you see a stable high (e.g. 8 bit times), you might want to call xSemaphoreGiveFromISR(), so your task will be woken up to process the received data.

A second method is installing a GPIO interrupt on the RX pin. When the interrupt fires you could register the current time and the RX value. This needs a high precision time, for instance the COUNT value of a fast running clock.

I have used both methods successfully. The GPIO interrupt gives a lower CPU load of course, but it is a bit more difficult to analyse the data.

Regards,  
Hein

---

<div class="post-metadata">

**Author:** ![system](https://d2v6vdsk2p900z.cloudfront.net/original/1X/7fc8fdb729c645aab5b20282bbe34e57cb407be6.jpeg) [@system](https://forums.freertos.org/u/system)\
**Post date:** [June 12, 2014, 11:00pm UTC](https://forums.freertos.org/t/exact-delay-cycles-in-freertos-task/1837/4 "2014-06-12T23:00:09Z")

</div>

**[jradoslav](https://sourceforge.net/u/jradoslav/)** wrote on [Thursday, June 12, 2014](https://sourceforge.net/p/freertos/discussion/382005/thread/52c7e56b/#bcb1):

this sequential code is OK tested

```auto

uint32_t bitDelayNS = 1000000000/baudRate;

int bcount = 8;

while(ioport_get_pin_level(pin));

delay_ns(bitDelayNS>>1);

 while(bcount--)
 {
	 delay_ns(bitDelayNS);
	 *recByte >>= 1;
	  if(ioport_get_pin_level(pin))
		  *recByte |= 0x80;
  }
 delay_ns(bitDelayNS);                

```

here is coded under itnerupt but bytes sent by stdio is corupted.  
timer is configured 10x faster half bit delay  
baud rate is 4800

```auto

#define TC TC0
#define CHANNEL 0
#define ID_TC ID_TC0
#define TC_Handler TC0_Handler
#define TC_IRQn TC0_IRQn
ioport_pin_t pin;

main()
{

    setpinAdr(&pin);

        printf("INIT OK\r\n");
	tc_config(96000); //periode is set 10*(half bit delay)

	   // Configure TC interrupts
	NVIC_DisableIRQ(TC_IRQn);
	NVIC_ClearPendingIRQ(TC_IRQn);
	NVIC_SetPriority(TC_IRQn,0);
	NVIC_EnableIRQ(TC_IRQn);

	while(1);
}

#define WAIT(n) (n*10)

 void TC_Handler(void)
{

	 uint32_t dummy;
	   dummy = tc_get_status(TC,CHANNEL);
	   UNUSED(dummy);

	   if(usartState == 0)
	   {
		   if(ioport_get_pin_level(pin))
		   {
			 ioport_toggle_pin_level(LED3_PIO);
			 usartState = 1;

			 cntBits = WAIT(3); //3 x 0.5 delay
			 bcount = 8;
		   }
	   }
	   cntBits--;

	   if(usartState > 0 && !cntBits)
	   {

		 switch(usartState)
		 {

			 case 1:
			 {
				if(bcount)
				{
					 recByte >>= 1;
					 if(ioport_get_pin_level(pin))
						  recByte |= 0x80;

					 cntBits = WAIT(2); // 1 bit delay 
					 --bcount;
				}
				else
				{
					 putchar(recByte);
					 cntBits = WAIT(2);
					 usartState = 2;
				}

			 }
			 break;
			 case 2:
				 usartState = 0;
				 break;

		 }

	   }

}

// Configuration function for the Timer.
static void tc_config(uint32_t freq_desired)
{
   // INPUTS:
   // freq_desired The desired rate at which to call the ISR, Hz.

   uint32_t ul_div;
   uint32_t ul_tcclks;
   uint32_t ul_sysclk = sysclk_get_cpu_hz();
   uint32_t counts;

   // Configure PMC
   pmc_enable_periph_clk(ID_TC);

   // Configure TC for a 4Hz frequency and trigger on RC compare.
   tc_find_mck_divisor(
      (uint32_t)freq_desired, // The desired frequency as a uint32.
      ul_sysclk, // Master clock freq in Hz.
      &ul_div, // Pointer to register where divisor will be stored.
      &ul_tcclks, // Pointer to reg where clock selection number is stored.
      ul_sysclk); // Board clock freq in Hz.
   tc_init(TC0, CHANNEL, ul_tcclks | TC_CMR_CPCTRG);

   // Find the best estimate of counts, then write it to TC register C.
      counts = (ul_sysclk/ul_div)/freq_desired;
   tc_write_rc(TC0, 0, counts);

   // Enable interrupts for this TC, and start the TC.
   tc_enable_interrupt(TC,
      CHANNEL,
      TC_IER_CPCS); // Enable interrupt.
   tc_start(TC,CHANNEL); // Start the TC.

}

```

---

<div class="post-metadata">

**Author:** ![htibosch](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/htibosch/32/62_2.png) [@htibosch](https://forums.freertos.org/u/htibosch)\
**Post date:** [June 13, 2014, 6:40am UTC](https://forums.freertos.org/t/exact-delay-cycles-in-freertos-task/1837/5 "2014-06-13T06:40:27Z")

</div>

**[heinbali01](https://sourceforge.net/u/heinbali01/)** wrote on [Friday, June 13, 2014](https://sourceforge.net/p/freertos/discussion/382005/thread/52c7e56b/#d6cf):

Hi Radoslav,

Your interrupt is not yet implemented the way it can work.

I attached a bit of code which isn’t perfect but it might give more ideas.

Regards,  
Hein

---

<div class="post-metadata">

**Author:** ![system](https://d2v6vdsk2p900z.cloudfront.net/original/1X/7fc8fdb729c645aab5b20282bbe34e57cb407be6.jpeg) [@system](https://forums.freertos.org/u/system)\
**Post date:** [June 13, 2014, 2:30pm UTC](https://forums.freertos.org/t/exact-delay-cycles-in-freertos-task/1837/6 "2014-06-13T14:30:46Z")

</div>

**[jradoslav](https://sourceforge.net/u/jradoslav/)** wrote on [Friday, June 13, 2014](https://sourceforge.net/p/freertos/discussion/382005/thread/52c7e56b/#8d4f):

thank you Hein

I have coded finall version of Software UART based on interrupts. edge detection start bit + timer counter that counter periode is max half delay of bit, freq = 2\*baudrate Hz.

it is enough to call the handler 2 times for 1 bit sampling, without any while waiting. After receiving 1 byte timer counter is disabled and edge detecotor enabled.

57600 baud rate on 84Mhz sam3x was ok.

code has no error detection.

here is core:  
complete code is attached

```auto

typedef enum
{
	eRS232_2400 = 2400,
	eRS232_4800 = 4800,
	eRS232_9600 = 9600,
	eRS232_19200 = 19200,
	eRS232_38400 = 38400,
	eRS232_57600 = 57600,
	eRS232_115200 = 115200,

}RS232Baud_t;

typedef struct structSWIRs232
{
	RS232Baud_t rs232Baud;
	void (*receiveByte)(char);
	Pio* pio;
	uint32_t pinNum;
	uint32_t PIO_ID;
	IRQn_Type PIO_IRQn;

}RS232SWI_t;
void rs232_int_receiver_init(RS232SWI_t* rs232);
void rs232_int_receiver_enable(RS232SWI_t* rs232);
void rs232_int_receiver_disable(RS232SWI_t* rs232);

///core

void pin_falling_edge_handler(uint32_t a,uint32_t b)
{

	 pio_disable_interrupt(rs232base->pio, (1u<<rs232base->pinNum));
	 halfBitDelayCount = 3; //wait 1.5 bit
	 bitCount = 8;
	 usartState = 1;
	 tc_start(TC,CHANNEL); //reset counter

}

void TC_Handler(void)
{

	 uint32_t ul_status= tc_get_status(TC,CHANNEL);

	 UNUSED(ul_status);

	   if(!(--halfBitDelayCount))
		   switch(usartState)
		   {
			   case 1:

					 recByte >>= 1;//ROR

					 if(pio_get(rs232base->pio ,rs232base->PIO_ID, (1u<<rs232base->pinNum)))
						  recByte |= 0x80; //CARRY bit

					 if(!(--bitCount))
						 usartState = 2;//wait stop bit

					 halfBitDelayCount = 2; //wait 1 bit

				   break;
			  case 2:

				  	  //stop bit level is high
				   	   usartState = 0;
				   	   tc_stop(TC,CHANNEL);
				   	   rs232base->receiveByte(recByte);// send to buffer management
				   	   pio_enable_interrupt(rs232base->pio, (1u<<rs232base->pinNum)); //wait for falling edge

			  break;
		   }

}

```

---

<div class="post-metadata">

**Author:** ![system](https://d2v6vdsk2p900z.cloudfront.net/original/1X/7fc8fdb729c645aab5b20282bbe34e57cb407be6.jpeg) [@system](https://forums.freertos.org/u/system)\
**Post date:** [June 13, 2014, 2:39pm UTC](https://forums.freertos.org/t/exact-delay-cycles-in-freertos-task/1837/7 "2014-06-13T14:39:34Z")

</div>

**[jradoslav](https://sourceforge.net/u/jradoslav/)** wrote on [Friday, June 13, 2014](https://sourceforge.net/p/freertos/discussion/382005/thread/52c7e56b/#056e):

```auto
//initialization 

RS232SWI_t config =
	{
			 .rs232Baud = 57600,
			 .pio = PIOA,
			 .pinNum = 26,
			 .PIO_ID = ID_PIOA,
			 .PIO_IRQn = PIOA_IRQn,
			 .receiveByte = &receiveByte

	};

	rs232_int_receiver_init(&config);
	rs232_int_receiver_enable(&config);

```

---

<div class="post-metadata">

**Author:** ![htibosch](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/htibosch/32/62_2.png) [@htibosch](https://forums.freertos.org/u/htibosch)\
**Post date:** [June 13, 2014, 5:42pm UTC](https://forums.freertos.org/t/exact-delay-cycles-in-freertos-task/1837/8 "2014-06-13T17:42:35Z")

</div>

**[heinbali01](https://sourceforge.net/u/heinbali01/)** wrote on [Friday, June 13, 2014](https://sourceforge.net/p/freertos/discussion/382005/thread/52c7e56b/#3097):

Hi Radoslav,

That looks great, good work!

It’s a good idea to use a GPIO interrupt on a falling edge to start the TC timer for recognition, and switch it off at the stop bit.  
Now it syncs on the start-bit, which should be good enough in most cases.

I made my algorithm to recognise a continuous stream of rs232 data from devices with a less precise clock and also for lower-quality hardware ( I want to be able to inform the hardware people and say: look at these errors! Otherwise software always gets the blame of a failure )

One remark: when you assign “usartState = 2”, you might want to “fall through” and stop the TC immediately, in order not the miss the GPIO interrupt of the next start bit?

TC interrupts may come too late, but never too early.

Wish you good luck,

Hein

---

<div class="post-metadata">

**Author:** ![system](https://d2v6vdsk2p900z.cloudfront.net/original/1X/7fc8fdb729c645aab5b20282bbe34e57cb407be6.jpeg) [@system](https://forums.freertos.org/u/system)\
**Post date:** [June 13, 2014, 11:32pm UTC](https://forums.freertos.org/t/exact-delay-cycles-in-freertos-task/1837/9 "2014-06-13T23:32:14Z")

</div>

**[jradoslav](https://sourceforge.net/u/jradoslav/)** wrote on [Friday, June 13, 2014](https://sourceforge.net/p/freertos/discussion/382005/thread/52c7e56b/#f8f3):

Thank you Hein

I think , the error detection can be implemented on higher layer (checksumm etc.),

last stop bit delay is probably nessesary , because pin\_falling\_edge\_handler can raise on last data bit. time-moment for pin reading is exactly in half periode of pin level state:

state time element:

t0\>----reading T/2----\<t1 , T = 1s/BaudRate,

this time-read-position is set by first 1,5T delays from start bit.

edge handler raise at time moment = (t0 state start bit) + few const cycles = C and C \<\< T.  
C is time for edge detection processing + handler subroutine call instructions.
