Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamixel2Arduino::begin() hangs if called after creating FreeRTOS tasks #115

Open
johnauld opened this issue Nov 30, 2022 · 0 comments
Open

Comments

@johnauld
Copy link

The problem is actually in SerialPortHandler::begin(), which calls delay(). This redirects to HAL_Delay(), which ultimately relies on the STM32 HAL's timer tick ISR running. However, calling into the FreeRTOS API apparently disables interrupts until the scheduler is started. Per https://www.freertos.org/FAQHelp.html:

If a FreeRTOS API function is called before the scheduler has been started then interrupts will deliberately be left disabled, and not re-enable again until the first task starts to execute.

HAL_Delay() spins until the tick count reaches the necessary value, but since the tick ISR is not running, the tick count never increments, and therefore HAL_Delay() never returns.

The following code demonstrates the problem:

#include <RTOS.h>
#include <Dynamixel2Arduino.h>

void setup() {
    Serial.begin(57600);
    while ( !Serial ) delay(10);

    Serial.print("Creating task 1: ");
    auto res = xTaskCreate([](void*) { while (true); }, "task1", 512, nullptr, 3, nullptr );
    Serial.println( (res == pdPASS) ? "succeeded" : "failed" );

    Dynamixel2Arduino   dxl {Serial3};
    dxl.begin(57600);                           // <---------------- ** hangs here **

    Serial.print("Creating task 2: ");
    res = xTaskCreate([](void*) { while (true); }, "task2", 512, nullptr, 3, nullptr );
    Serial.println( (res == pdPASS) ? "succeeded" : "failed" );

    Serial.println("Starting scheduler");
    vTaskStartScheduler();
    Serial.println("Failed to start scheduler");
}

void loop() {}  // No-op under FreeRTOS

The comment ** hangs here ** shows the location of the problem. Dynamixel2Arduino::begin() calls SerialPortHandler::begin(). I added some instrumentation to the latter function to trace execution by turning on board LEDs:

void SerialPortHandler::begin(unsigned long baud)
{
digitalWrite(BDPIN_LED_USER_1, LOW);                                    // <---- This line executes
#if defined(ARDUINO_OpenCM904)
  if(port_ == Serial1 && getOpenState() == false){
    Serial1.setDxlMode(true);
  }
#elif defined(ARDUINO_OpenRB)
  if(port_ == Serial1 && getOpenState() == false){
    pinMode(BDPIN_DXL_PWR_EN, OUTPUT);
    digitalWrite(BDPIN_DXL_PWR_EN, HIGH);
    delay(300); // Wait for the FET to turn on.
  }
#elif defined(ARDUINO_OpenCR)
  if(port_ == Serial3 && getOpenState() == false){
    pinMode(BDPIN_DXL_PWR_EN, OUTPUT);
    digitalWrite(BDPIN_DXL_PWR_EN, HIGH);
  }
digitalWrite(BDPIN_LED_USER_2, LOW);                                    // <---- This line executes
  delay(300); // Wait for the DYNAMIXEL to power up normally.
digitalWrite(BDPIN_LED_USER_3, LOW);                                    // <---- This line is never reached
#endif
digitalWrite(BDPIN_LED_USER_4, LOW);

  baud_ = baud;
  port_.begin(baud_);
  mbedTXdelayus = 24000000 / baud;

  if(dir_pin_ != -1){
    pinMode(dir_pin_, OUTPUT);
    digitalWrite(dir_pin_, LOW);
    while(digitalRead(dir_pin_) != LOW);
  }

  setOpenState(true);
}
johnauld pushed a commit to johnauld/Dynamixel2Arduino that referenced this issue Aug 8, 2023
@johnauld johnauld mentioned this issue Aug 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant