Quality RTOS & Embedded Software

 Real time embedded FreeRTOS RSS feed 
Quick Start Supported MCUs PDF Books Trace Tools Ecosystem TCP & FAT




Loading

Task acting strangley when used inside C++ classes on AVR Atmega2560 uC

Posted by simplethings07 on August 1, 2017

Hello guys,

I am using AVR-GCC on AVR Atmega2560 uC with FreeRTOS v9. So basically I want to implement a simple radar with ultrasonic sensor and a servo motor. When I run servo motor and ultrasonic sensor on seperate tasks in my main.cpp, everything works just fine. Then I tried to wrap these 2 threads inside Radar class:

~~~ Radar::Radar(UltrasonicSensor* ultrasonicSensor, Servo* servo) { this->ultrasonicSensor = ultrasonicSensor; this->servo = servo;

this->objectAngle = 0;
this->objectDistance = 0;

xTaskCreate(
   Radar::ultrasonicThread
,  NULL  // A name just for humans
,  128  // Stack size
,  this
,  2  // priority
,  NULL );

xTaskCreate(
   Radar::servoThread
,  NULL  // A name just for humans
,  128  // Stack size
,  this
,  2  // priority
,  NULL );

}

void Radar::ultrasonicThread(void* pvParameters) { Radar* radarInstance;

radarInstance = static_cast<class Radar*>(pvParameters);

while (true)
{
	radarInstance->ultrasonicSensor->read( &(radarInstance->objectDistance) );
}

}

void Radar::servoThread(void* pvParameters) { int8_t angle; Radar* radarInstance;

radarInstance = static_cast<class Radar*>(pvParameters);

while (true)
{
	for ( angle = 0; angle < 180; ++angle )
	{
	  radarInstance->servo->write(angle);
	  radarInstance->objectAngle = angle;
	  vTaskDelay(20 / portTICK_PERIOD_MS);
	}

	for ( angle = 180; angle > 0; --angle )
	{
	  radarInstance->servo->write(angle);
	  radarInstance->objectAngle = angle;
	  vTaskDelay(20 / portTICK_PERIOD_MS);
	}
}

}

void Radar::open(void) {vTaskStartScheduler();}

int8t Radar::read(uint8t* distance, uint8_t* angleInDegres) { *angleInDegres = this->objectAngle; *distance = this->objectDistance;

return 0;

} ~~~

You can see that I have servoThread and ultrasonicThread, and I am doing exactly the same thing as I did in my main.cpp, where it worked just fine.

~~~

HardwareSerial& btSrialPort = Serial3; HardwareSerial& pcSerialPort = Serial; Servo servoMotor; UltrasonicSensor ultrasonicSensor(trigPin, echoPin); MessageProcessor messageProcessor(&btSrialPort); Radar radar(&ultrasonicSensor, &servoMotor);

uint8t distance; uint8t angle;

void radarThread(void* pvParameters) { uint8_t angle, distance;

while (true) { radar.read(&distance, &angle); pcSerialPort.println(distance); } }

void setup() { pcSerialPort.begin (9600); btSrialPort.begin(9600);

pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT);

servoMotor.attach(servoPin);

multiThreadingBootstrap(); }

void loop() {

}

void multiThreadingBootstrap(void) {

xTaskCreate( radarThread , (const portCHAR *)"Radar" // A name just for humans , 128 // Stack size , NULL , 2 // priority , NULL );

radar.open(); vTaskStartScheduler(); }

~~~

You can see that in function multiThreadingBootstrap I create a new thread called radarThread, which then calls method ** Radar::read, which returns 2 parameters that are read from two thread methods: **Radar::servoThread and Radar::ultrasonicThread.

When I use it this way my ultrasonic sensor acts strangely, it detects objects with delay, servo motor goes only in one direction. Could a problem lay in the fact that I have two threads running inside C++ class and one thread running in my main.cpp ?


Task acting strangley when used inside C++ classes on AVR Atmega2560 uC

Posted by simplethings07 on August 2, 2017

Anyone?


Task acting strangley when used inside C++ classes on AVR Atmega2560 uC

Posted by rtel on August 2, 2017

Sorry, we only ever test with C rather than C++, but there are some C++ wrappers for FreeRTOS on the web and in the FreeRTOS Interactive site, for example: https://interactive.freertos.org/hc/en-us/community/posts/210028906-Using-FreeRTOS-with-C-


Task acting strangley when used inside C++ classes on AVR Atmega2560 uC

Posted by hs2sf on August 2, 2017

Seems that you starting the scheduler twice in multiThreadingBootstrap(): 1st in radar.open() and 2nd explicitely right below. That could cause problems I guess ;)


Task acting strangley when used inside C++ classes on AVR Atmega2560 uC

Posted by richard_damon on August 3, 2017

You don't show the class definition, but one thing that might be the issue is that the thread functions can't be normal methods of the class, as that will have extra parameter (this) that is implied. Technically, even static member functions might not be compatibld, but normally are. To be absolutely sure, the base task function should be a free function that has been declared with extern "C" linkage (which I don't think can be made a member of a class).

The two vTaskStartScheduler won't be a problem, as the first call will never return.


Task acting strangley when used inside C++ classes on AVR Atmega2560 uC

Posted by simplethings07 on August 3, 2017

Here is my class definition, for the previous post:

Radar.h ~~~

ifndef RADARH_
define RADARH_
include

class Servo; class UltrasonicSensor;

class Radar { private: UltrasonicSensor* ultrasonicSensor; Servo* servo; uint8t objectDistance; uint8t objectAngle;

public:
	Radar(UltrasonicSensor* ultrasonicSensor, Servo* servo);
	int8_t read(uint8_t* distance, uint8_t* angleInDegres);
	Radar* getInstance() { return this; }
	void open(void);

private:
	static void ultrasonicThread(void* parameter);
	static void servoThread(void* parameter);

};

~~~ you can see that both ultrasonicThread and servoThread are static. I couldn't even compile my code with non-static class methods as task functions, since compiler would give me an error. I tried to follow your suggestion, but it gives the same result:

Radar.h ~~~ extern "C" void ultrasonicSensorThread(void* pvParameters); extern "C" void servoMotorThread(void* pvParameters);

class Radar { private: UltrasonicSensor* ultrasonicSensor; Servo* servo; uint8t objectDistance; uint8t objectAngle;

public:
	Radar(UltrasonicSensor* ultrasonicSensor, Servo* servo);
	int8_t read(uint8_t* distance, uint8_t* angleInDegres);
	Radar* getInstance() { return this; }
	void open(void);

private:
	friend void ultrasonicSensorThread(void* pvParameters);
	friend void servoMotorThread(void* pvParameters);

private:
	static void ultrasonicThread(void* parameter);
	static void servoThread(void* parameter);

}; ~~~

Radar.cpp ~~~ void ultrasonicSensorThread(void* pvParameters) { Radar* radarInstance;

radarInstance = static_cast<class Radar*>(pvParameters);

while (true)
{
	radarInstance->ultrasonicSensor->read( &(radarInstance->objectDistance) );
}

}

void servoMotorThread(void* pvParameters) { int8_t angle; Radar* radarInstance;

radarInstance = static_cast<class Radar*>(pvParameters);

while (true)
{
	for ( angle = 0; angle < 180; ++angle )
	{
	  radarInstance->servo->write(angle);
	  radarInstance->objectAngle = angle;
	  vTaskDelay(20 / portTICK_PERIOD_MS);
	}

	for ( angle = 180; angle > 0; --angle )
	{
	  radarInstance->servo->write(angle);
	  radarInstance->objectAngle = angle;
	  vTaskDelay(20 / portTICK_PERIOD_MS);
	}
}

}

Radar::Radar(UltrasonicSensor* ultrasonicSensor, Servo* servo) { this->ultrasonicSensor = ultrasonicSensor; this->servo = servo;

this->objectAngle = 0;
this->objectDistance = 0;

xTaskCreate(
   ultrasonicSensorThread
,  NULL  // A name just for humans
,  128  // Stack size
,  this
,  2  // priority
,  NULL );

xTaskCreate(
   servoMotorThread
,  NULL  // A name just for humans
,  128  // Stack size
,  this
,  2  // priority
,  NULL );

} ~~~


Task acting strangley when used inside C++ classes on AVR Atmega2560 uC

Posted by richard_damon on August 4, 2017

one thing I see that looks strange: int8_t angle ... for(angle = 0; angle < 180; angle++) {

since the range of an int8_t is -128 to 127, this loop will never end, as angle will NEVER be above 180.


Task acting strangley when used inside C++ classes on AVR Atmega2560 uC

Posted by simplethings07 on August 4, 2017

Richard Damon you really have a good eye, I didn't notice that. Somehow I wrote int8t instead of uint8t there, you can see that my uint8t Radar::objectAngle member field is type of uint8t already. Thank you, now it works like a charm! Now atleast I am sure that I can use FreeRTOS in C++! One more question guys, is there way to use sleep inside a thread given in milliseconds. Something like:

~~~ vTaskDelay(10 / portTICKPERIODUS); ~~~


Task acting strangley when used inside C++ classes on AVR Atmega2560 uC

Posted by hs2sf on August 4, 2017

Yes, of course. I'm using this (for non C++11 compiler replace auto w/ the appropriate type): ~~~ //! BSD style (non-POSIX) msleep void msleep( uint32t TimeMS ) { auto TimeTicks = (TimeMS + portTICKPERIODMS -1) / portTICKPERIODMS; //!< round up to mult. of portTICKPERIOD_MS vTaskDelay( TimeTicks ); }

~~~


Task acting strangley when used inside C++ classes on AVR Atmega2560 uC

Posted by richard_damon on August 4, 2017

I will admit that I make the same mistake at times myself. soo something I get used to catching. Small comment, you are perhaps prematurly over optimizing things by making a local angle variable an 8 bit type. I am much more apt to use int for something like this. Fixed size types are mostly used in storage structures, computations tend to be in natual sized types. Angles in degress will normally be at least an int16_t as the base domain for an angle is 0..360 (or -180 .. 180). Jusgt because a particular angle is in a more limited range (-90 ... 90 or 0 ...180) isn't normally a big enough of a reason to reduce the range to an 8 bit type. (Big tables might be a possible exception).


Task acting strangley when used inside C++ classes on AVR Atmega2560 uC

Posted by davidbrown on August 4, 2017

If that bug was not caught by your static error checking, you need to bump up your warnings! With gcc, this is -Wtype-limits, or -Wextra.

Making good use of your tools can save a lot of time and effort.


Task acting strangley when used inside C++ classes on AVR Atmega2560 uC

Posted by simplethings07 on August 4, 2017

I am using Atmel Studio 7, I have just checked Warnings http://imgur.com/fVFJnmj . seems like All warnings box has been already checked.


Task acting strangley when used inside C++ classes on AVR Atmega2560 uC

Posted by simplethings07 on August 4, 2017

The servomotor can only move half of circle (0 - +180 or -90 - +90 as you mentioned). Since this is 8bit microcontroller I try to squeeze everything.


Task acting strangley when used inside C++ classes on AVR Atmega2560 uC

Posted by simplethings07 on August 4, 2017

Sorry I wrote miliseconds instead of microseconds. I wanted to ask whether we can specify delay in microseconds to vTaskDelay function.


Task acting strangley when used inside C++ classes on AVR Atmega2560 uC

Posted by davidbrown on August 4, 2017

Like all IDE's, Atmel Studio gives you a very simiplified view of the compiler options. It's not too bad for getting started, but much of the power of the compiler is hidden. I haven't used that IDE for many years (it is Windows only), but somewhere it will have a place for adding your own compiler options. Add "-Wextra" to that.

I would also recommend spending some time reading the compiler documentation for the particular tool version you have. There are many warning options that can help you write better code, and spot mistakes. Not everyone thinks compiler manuals are fun to read (I do, and have read several pretty much cover-to-cover). But it is important to know your tools - especially because many of the nice bits are off by default.


Task acting strangley when used inside C++ classes on AVR Atmega2560 uC

Posted by richard_damon on August 5, 2017

Delaying in microseconds, Delays to things like vTaskDelay will; be in units of ticks, you could always define something like portTICKPERIODMICROSEC, but you still won't get a finer resolution.

One big issue is that the cost to run the scheduler can easily be big enough on many processors that such a delay is impractical. If you really need a delay of a few microseconds, it is generally reasonable to just spin wait, maybe looking at a timer (like the systick counter) to control the period.

As to the 8 bit local values, if you really need to squeeze the design that much, the overhead of C++ may be worse.


Task acting strangley when used inside C++ classes on AVR Atmega2560 uC

Posted by hs2sf on August 5, 2017

C++ 'overhead' strongly depends on the features used. Using classes ie. OO style programming doesn't cost anything you don't want. When using e.g. exceptions or RTTI you've to pay for, of course.


Task acting strangley when used inside C++ classes on AVR Atmega2560 uC

Posted by simplethings07 on August 5, 2017

With all due Respect Richard, C++ has no overhead when compared to C when used properly. That is why it was invented by Stroustrup in the first place. It gives you the same speed as C and level abstraction in your code. Yes it has overhead when using excpetions as HS2 said, but AVR-GCC doesn't support exceptions anyways. You may have overhead also when using polymorphism, but it's ONE extra PUSH operation , since compiler has to take a look in v_table, or for example when you use inhertance. But I always stick to rule from C# & Java by using interfaces withouth multiple inheritance. My code sizes in C++ compared to ones in C are the exact same size. And C++ is a strong tool, it gives you a level of abstraction, which enables you to write more readable code, more maintanable and most important resuable code with encapsulation of data, which makes your code less prone to errors. So I do not see why people alywas come with overhad of C++ thing. I would always choose OOP language compared to sequencial languages like C.


Task acting strangley when used inside C++ classes on AVR Atmega2560 uC

Posted by richard_damon on August 5, 2017

Generally, I agree with that, C++ can be a very low cost additioon (which is why I wrote my C++ wrappers). In this case though, he was so worried about size that he was automatically making the bug threatening size reduction of an angle variable to save 1 BYTE of memory. Declaring an out-of-line constructor can cost that much by forcing a function call.

My point is more that if he feels it is ok to use C++, he shouldn't be starting at that level of hand optimizing memory usage in other places.


[ Back to the top ]    [ About FreeRTOS ]    [ Sitemap ]    [ ]




Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.

Latest News

FreeRTOS kernel V10 is available for immediate download. Now MIT licensed.


FreeRTOS Partners

ARM Connected RTOS partner for all ARM microcontroller cores

IAR Partner

Microchip Premier RTOS Partner

RTOS partner of NXP for all NXP ARM microcontrollers

STMicro RTOS partner supporting ARM7, ARM Cortex-M3, ARM Cortex-M4 and ARM Cortex-M0

Texas Instruments MCU Developer Network RTOS partner for ARM and MSP430 microcontrollers

OpenRTOS and SafeRTOS