I am trying to use a semaphore of the arduino core for ESP32. My code is a follows:
#include <Arduino.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#define configUSE_MUTEXES 1
#define configUSE_COUNTING_SEMAPHORES 1
void vTaskExample(void *pvParameters);
void accessSharedResource{}
volatile SemaphoreHandle_t xResourceSemaphore = NULL;
void setup()
{
xTaskCreatePinnedToCore(&vTaskExample, "example task", 1024, NULL, 2, NULL, 1);
}
void loop()
{
// Do nothing
}
void vTaskExample(void *pvParameters)
{
vSemaphoreCreateBinary(xResourceSemaphore);
while (true)
{
if (xSemaphoreAltTake(xResourceSemaphore, (TickType_t)0))
{
accessSharedResource();
xSemaphoreAltGive(xResourceSemaphore);
}
}
}
Unfortunately, during compilation (in the linking phase to be exact), I get the following error message:
main.cpp:(.text._Z12vTaskExamplePv+0x37): undefined reference to `xQueueAltGenericReceive'
main.cpp:(.text._Z12vTaskExamplePv+0x4b): undefined reference to `xQueueAltGenericSend'
I have looked up the freeRTOS documentation, and it indicates that the two functions are located in the queue.h; thus, should be available. Also, I have set the necessary freeRTOS configuration by setting configUSE_MUTEXES and configUSE_COUNTING_SEMAPHORES flags
Any suggestions why this does not compile?
Only prototypes are provided in queue.h - nothing executable. If you look at the FreeRTOS documentation you will note that the alternative API has been deprecated for a long time, and is only included in the build if configUSE_ALTERNATIVE_API is set to 1.
Related
Currently I am trying to attach a pin interrupt whose ISR is to call xTaskResumeFromISR or xQueueSendFromISR. The ISR gets called correctly, but the code to execute results in a core 0 panic.
Here are the implementation details.
PlatformIO: platform = espressif32 # 6.0.1, framework = arduino, board = esp32dev
Header file (Worker.h)
#pragma once
#include <Arduino.h>
class Worker {
public:
Worker(uint8_t pinExtInterrupt);
bool startTask(void);
protected:
// static wrapper for task creation
static void staticRun(void *arg) {
reinterpret_cast<Worker *>(arg)->run();
}
// actual task's logic
void run(void);
// static interrupt handler
static void staticIsrHandler(void* arg);
// actual interrupt handler
void isrHandler();
TaskHandle_t _taskHandle = nullptr;
uint8_t _pinExtInterrupt;
};
Source file (Worker.cpp)
#include "Worker.h"
Worker::Worker(uint8_t pinExtInterrupt) {
_pinExtInterrupt = pinExtInterrupt;
pinMode(pinExtInterrupt, INPUT);
}
bool Worker::startTask(void) {
BaseType_t xReturned = xTaskCreate(staticRun, "Worker", 2048, this, 5, &_taskHandle);
gpio_set_intr_type(static_cast<gpio_num_t>(_pinExtInterrupt), GPIO_INTR_NEGEDGE);
gpio_install_isr_service(0);
gpio_isr_handler_add(static_cast<gpio_num_t>(_pinExtInterrupt), staticIsrHandler, NULL);
return true;
}
void Worker::run(void) {
for (;;) {
vTaskSuspend(NULL);
// LOGIC
}
}
void IRAM_ATTR Worker::staticIsrHandler(void* arg) {
reinterpret_cast<Worker*>(arg)->isrHandler();
}
void IRAM_ATTR Worker::isrHandler() {
xTaskResumeFromISR(_taskHandle); // ###### THIS LINE THROWS THE EXCEPTION ######
}
Error
Error: Core 0 panic'ed (LoadProhibited). Exception was unhandled.
0x400d1d00:0x3ffbeaac in Worker::isrHandler() at ...
But what works is if you replace xTaskResumeFromISR e.g. with digitalWrite(..).
Need to fix the problem above.
Your call here:
gpio_isr_handler_add(static_cast<gpio_num_t>(_pinExtInterrupt), staticIsrHandler, NULL);
assigns a null pointer for the ISR handler's context data. As a result, when your static ISR is called:
void IRAM_ATTR Worker::staticIsrHandler(void* arg) {
reinterpret_cast<Worker*>(arg)->isrHandler();
}
arg is a null pointer, causing the access to _taskHandle to fail here:
void IRAM_ATTR Worker::isrHandler() {
xTaskResumeFromISR(_taskHandle);
}
If you replace your gpio_isr_handler_add call with the following:
gpio_isr_handler_add(static_cast<gpio_num_t>(_pinExtInterrupt), staticIsrHandler, this);
everything should work.
I am writing an Arduino project and try to wrap my own class around the DHT (Sensor) library (https://github.com/adafruit/DHT-sensor-library/blob/master/examples/DHT_Unified_Sensor/DHT_Unified_Sensor.ino or that https://github.com/adafruit/DHT-sensor-library/blob/master/examples/DHTtester/DHTtester.ino).
I wanna abstract my own Library with functions and use that to learn C++.
But I have a problem when I try to instantiate my own class:
lib/Hythe/Hythe.cpp: In constructor 'Hythe::Hythe(uint8_t, uint8_t)':
lib/Hythe/Hythe.cpp:3:47: error: no matching function for call to 'DHT::DHT()'
Hythe::Hythe(uint8_t dht_pin, uint8_t dht_type)
Can someone please tell me how to declare, instantiate and call the DHT class within my own class?
When I implement DHT
main.cpp
#include "Hythe.h"
Hythe hythe(HYTHE_PIN, HYTHE_TYPE); // here I instantiate the sensor.
void setup()
{
hythe.getSensorInfo();
}
Hythe.h
#include "SPI.h"
#include "Wire.h"
#include <DHT.h>
class Hythe
{
private:
float temperature;
float humidity;
uint32_t delayMS;
public:
Hythe(uint8_t, uint8_t); // init with PIN and TYPE
DHT _dht; // THIS IS CAUSING THE ERROR
// (It's in the header file. I simply wanna declare it and
// call it in the cpp file later).
// When I remove this line I get:
// "error: '_dht' was not declared in this scope"
unsigned char getTemperature(); // read the temperature
void getSensorInfo(); // returns sensor info
};
Hythe.cpp
#include "Hythe.h"
Hythe::Hythe(uint8_t dht_pin, uint8_t dht_type)
{
Serial.print(dht_pin);
_dht = DHT(dht_pin, dht_type);
}
unsigned char Hythe::getTemperature()
{
return 0;
}
void Hythe::getSensorInfo()
{
Serial.println(F("------------------------------------"));
Serial.println(F("Temperature Sensor"));
}
As Vlad points out, DHT has no default constructor. You want to use initializer list to avoid calling a default constructor. You can directly call DHT's constructor in the initializer list this way.
Hythe::Hythe(uint8_t dht_pin, uint8_t dht_type): _dht(dht_pin, dht_type)
{
Serial.print(dht_pin);
}
I am trying to create a new class that controls two servos.
My code compiles just fine. However, when I run it, the servos just turn all the way to one direction. This seems to happen when I try instantiating the class (when in the constructor, I attach the servos in the class to pins).
In My class's header file, I have
[UPDATED]
#ifndef ServoController_h
#define ServoController_h
#include "Arduino.h"
#include <Servo.h>
class ServoController
{
public:
ServoController(int rotateServoPin, int elevateServoPin);
void rotate(int degrees);
void elevate(int degrees);
private:
Servo rotateServo;
Servo elevateServo;
int elevationAngle;
int azimuthAngle;
};
#endif
Code so far for my Class:
#include "Arduino.h"
#include "ServoController.h"
ServoController::ServoController(int rotateServoPin, int elevateServoPin)
{
azimuthAngle = 0;
elevationAngle = 0;
elevateServo.attach(elevateServoPin);
rotateServo.attach(rotateServoPin);
}
void ServoController::rotate(int degrees)
{
//TO DO
rotateServo.write(degrees);
}
void ServoController::elevate(int degrees)
{
//TO DO
elevateServo.write(degrees);
}
And finally my arduino sketch so far is just:
#include <ServoController.h>
#include <Servo.h>
ServoController sc(2 , 3);
void setup()
{
}
void loop()
{
}
I'm pretty sure the circuit I am using is fine, since if I do not use my class, and just use the servo library directly in my arduino file, the servos move correctly.
any ideas why this might happen?
[UPDATE]
I actually got this working. In my constructor, I have removed the lines to attach the servos to pins. Instead, I have added another method to my class which does the attachment.
ServoController::ServoController(int rotateServoPin, int elevateServoPin)
{
azimuthAngle = 0;
elevationAngle = 0;
// elevateServo.attach(elevateServoPin);
// rotateServo.attach(rotateServoPin);
}
void ServoController::attachPins(int rotateServoPin, int elevateServoPin)
{
azimuthAngle = 0;
elevationAngle = 0;
elevateServo.attach(elevateServoPin);
rotateServo.attach(rotateServoPin);
}
I then call this in my sketch's setup() function:
void setup()
{
sc.attachPins(2,3);
}
It seems like if I attach my servos outside of the setup() function, my problem occurs.
[UPDATE July 27 9:13PM]
Verified something with another test:
I created a new sketch where I attached a servo before setup():
#include <Servo.h>
Servo servo0;
servo0.attach(2);
void setup()
{
}
void loop() // this function runs repeatedly after setup() finishes
{
servo0.write(90);
delay(2000);
servo0.write(135);
delay(2000);
servo0.write(45);
delay(2000);
}
When I try to compile, Arduino throws an error:
"testservotest:4: error: expected constructor, destructor, or type conversion before '.' token"
So there was an error, but it was not thrown when the attach method was called from a class
Thanks very much
The call to servo0.attach() needs to be inside the setup routine:
#include <Servo.h>
Servo servo0;
void setup(){
servo0.attach(2);
}
As you discovered with your attachServo routine. You don't need the extra routine, just call attach method inside the setup.
If what you want it in a class, you will have to have a method in the class to do the pin assignment, and call this method either in setup() (one time assignment) or in loop() (dynamic assignment during program execution).
Pin assignment cannot be done in the constructor of a global variable when using the Servo.h library as the timer used to manage the servo output get corrupted between the time you create the object and the time setup() is executed.
The code that I have posted below, is basically used to get (continuous streaming data) from a software and display that data as it is received. The issue that I am facing is, that the software (which already has the "server") is on Windows, but I need to get the data on a separate system running Linux (Ubuntu).
Can anyone guide me regarding what changes do I need to make to the code in-order to make it work on Linux?
Also since they are "communicating" over a network, will there be any changes in the code to point to the server on the windows machine? ( I am sorry for such terminology, I am a bit new to this, so please correct me if I am mistaken)
#include "vrpn_Connection.h" // Missing this file? Get the latest VRPN distro at
#include "vrpn_Tracker.h" // ftp://ftp.cs.unc.edu/pub/packages/GRIP/vrpn
#include "conio.h" // for kbhit()
//== Callback prototype ==--
void VRPN_CALLBACK handle_pos (void *, const vrpn_TRACKERCB t);
//== Main entry point ==--
int main(int argc, char* argv[])
{
vrpn_Connection *connection;
char connectionName[128];
int port = 3883;
sprintf(connectionName,"localhost:%d", port);
connection = vrpn_get_connection_by_name(connectionName);
vrpn_Tracker_Remote *tracker = new vrpn_Tracker_Remote("Tracker", connection);
tracker->register_change_handler(NULL, handle_pos);
while(!kbhit())
{
tracker->mainloop();
connection->mainloop();
Sleep(5);
}
return 0;
}
//== Position/Orientation Callback ==--
void VRPN_CALLBACK handle_pos (void *, const vrpn_TRACKERCB t)
{
printf("Tracker Position:(%.4f,%.4f,%.4f) Orientation:(%.2f,%.2f,%.2f,%.2f)\n",
t.pos[0], t.pos[1], t.pos[2],
t.quat[0], t.quat[1], t.quat[2], t.quat[3]);
}
I would appreciate if anyone could suggest an "easier" alternate to this as well. Thank you!
kbhit() and Sleep() functions are exclusive to Windows.
Here you don't really need kbhit function. You can use an infinite loop instead.
For the sleep method, you can use this code from this thread :
Sleep function in C++
#ifdef _WIN32
#include <windows.h>
void sleep(unsigned milliseconds)
{
Sleep(milliseconds);
}
#else
#include <unistd.h>
void sleep(unsigned milliseconds)
{
usleep(milliseconds * 1000); // takes microseconds
}
#endif
But a much simpler method is to use boost::this_thread::sleep.
This code should work on Linux and Windows.
//...
while(1)
{
tracker->mainloop();
connection->mainloop();
sleep(5000);
}
//...
I'm writing a simple library for an ultrasonic distance sensor and thought i'd try using interrupts.
However i can't set my functions in the attachCallback method properly.
I want HCSR04Interrupt::echoHigh() and HCSR04Interrupt::echoLow() called when the pin goes high and low respectively.
I've Googled this to no avail. The Ardiuno IDE says the following:
./Arduino/libraries/HCSR04/HCSR04Interrupt.cpp: In member function 'void HCSR04Interrupt::getDistance()':
./Arduino/libraries/HCSR04/HCSR04Interrupt.cpp:31: error: argument of type 'void (HCSR04Interrupt::)()' does not match 'void (*)()'
./Arduino/libraries/HCSR04/HCSR04Interrupt.cpp: In member function 'void HCSR04Interrupt::echoHigh()':
./Arduino/libraries/HCSR04/HCSR04Interrupt.cpp:47: error: argument of type 'void (HCSR04Interrupt::)()' does not match 'void (*)()'
Here is my header:
#ifndef _HCSR04Interrupt_
#define _HCSR04Interrupt_
#include "Arduino.h"
#define HCSR04_CM_FACTOR 58.0
#define HCSR04_IN_FACTOR 148.0
#define HCSR04_CM_MODE 0
#define HCSR04_IN_MODE 1
class HCSR04Interrupt {
public:
double distance;
HCSR04Interrupt(int trigger_pin, int echo_pin, void (*callback)());
void setUnits(int units);
void getDistance();
private:
int _trigger_pin;
int _echo_pin;
int _units;
unsigned long _micros_start;
void (*_callback)();
void initialize();
void echoHigh();
void echoLow();
};
#endif
And my implementation (not complete since i cant get past the attachInterrupt step):
#include "Arduino.h"
#include "HCSR04Interrupt.h"
HCSR04Interrupt::HCSR04Interrupt(int trigger_pin, int echo_pin, void (*callback)()) {
_trigger_pin = trigger_pin;
_echo_pin = echo_pin;
_callback = callback;
initialize();
}
void HCSR04Interrupt::setUnits(int units) {
_units = units;
}
void HCSR04Interrupt::initialize() {
pinMode(_trigger_pin, OUTPUT);
pinMode(_echo_pin, INPUT);
digitalWrite(_trigger_pin, LOW);
}
void HCSR04Interrupt::getDistance() {
//Listen for the RISING interrupt
attachInterrupt(_echo_pin - 2, echoHigh, RISING);
//The trigger pin should be pulled high,
digitalWrite(_trigger_pin, HIGH);
//for 10 us.
delayMicroseconds(20);
//Then reset it.
digitalWrite(_trigger_pin, LOW);
}
void HCSR04Interrupt::echoHigh() {
_micros_start = micros();
detachInterrupt(_echo_pin - 2);
attachInterrupt(_echo_pin - 2, echoLow, FALLING);
}
void HCSR04Interrupt::echoLow() {
detachInterrupt(_echo_pin - 2);
unsigned long us = micros() - _micros_start;
distance = us;
(*_callback)();
}
So the compiler (not the IDE) tells you exactly what's wrong:
argument of type 'void (HCSR04Interrupt::)()' does not match 'void (*)()
So, while attachInterrupt() takes a function pointer of type void (*)(), you're trying to pass it a non-static member function, which you can't. You can try making the member function static and casting:
static void echoHigh();
// ...
attachInterrupt(_echo_pin - 2, reinterpret_cast<void (*)()>(&echoHigh), RISING);
Arduino interrupt handlers can only be functions. You are trying make method of an object an interrupt handler. Hence the compiler complains.
To be more precise about it, object methods are like functions, but it is as if they take a "hidden" parameter, which specifies the object instance. Therefore, they actually have different type signatures from plain functions. This disallows one to pass a method pointer when what a function is looking for is a plain function pointer.
The solution is to move your echoHigh() and echoLow() out of the HCSR04Interrupt class, and make them plain functions.
As I stumbled upon this question and it hasn't had an accepted answer, I write what I found, which worked for me:
The interrupt has to be called by a global wrapper. This wrapper needs to call a handleInterupt function of the class. Therefore it has to know the class. This can be done by storing it in a global variable. If multiple instances of the class should be used, multiple such global variables have to be used. But as the interrupt pins are just a few you can write a global variable and function for every pin:
MyClass theInstance_pin3 = NULL;
MyClass theInstance_pin7 = NULL;
// Somewhere, fill in an initialized copy of MyClass,
// and set theInstance_pin3 or theInstance_pin7 to it
void ISR_3()
{
if (theInstance_pin3)
theInstance_pin3->handleInterrupt();
}
void ISR_7()
{
if (theInstance_pin7)
theInstance_pin7->handleInterrupt();
}
as a reference see: http://forum.arduino.cc/index.php?topic=41713.0
or http://forum.arduino.cc/index.php?topic=160101.0
I got around this by making a singleton base class which represents the hardware as a whole (which kinda makes sense in this situation anyway).
Any function pointers can then be passed to the sub-component class, and handled by the singleton, whose member variables and methods are all static.
Example headers (untested):
// Sub-component
class LampButton {
public:
LampButton(int pin, void(*pushHandler)());
}
// Sub-component
class LampLed {
public:
LampLed(int pin);
void toggle();
}
// Singleton represents the hardware in it's entirety
class Lamp {
public:
// Call this instead of a constructor
static void initialize(int buttonPin, int ledPin);
// Function implemented inline for clarity - don't do this
static void handleButtonPush() {
led.toggle();
}
private:
static LampButton button;
static LampLed led;
}