junkfix / esp32-ds18b20

Arduino Library for ESP32 DS18B20 Non Blocking Onewire RMT protocol, no dependencies, minimal
MIT License
15 stars 4 forks source link

RMT missfuncion #11

Closed sirpete83 closed 1 month ago

sirpete83 commented 1 month ago

I have an impossible problem with an RMT function. Perhaps you have an idea that can help me. First I used the "OneWire" library for my DS1820. I currently have 4 sensors connected. In my project I then built a tone generator that should output a sequence of tones using RMT. I configured it as in the code below and triggered a function via telnet as a test, which then outputs the tone. Unfortunately I discovered that the tones were much too long and did not correspond to the calculated times. I then checked the frequencies and there does not seem to be an error. The next step was to gradually deactivate parts of the program and see when the RMT module works normally again. The solution was to switch off the entire OneWire function. On closer inspection I discovered that this library deactivates the interrupts for the bitbang implementation of the onewire. I concluded that it is not a good idea for an RTOS system that is clocked via hardware timers. And I assumed that using your library, which also uses RMT, would not interfere with the other parts of the processor. After I had rebuilt the code and was able to read the temperatures again, I noticed that my RMT module behaves in the same way as the other library. The beeps are at least 20x longer than they should be.

I have to say that the application is a bit more complex in my opinion. In addition to the standard task that is automatically generated, I have WLAN and 3 other tasks. But they don't run particularly quickly. All tasks have priority 1, one task for the web server, one to send MQTT data, one to query sensors. In this task, the DS1820 is also queried, among other things.

Today I want to try to stop the task for querying the sensors when a signal is output. I could live with this workaround, but of course it would be better to understand where the phenomenon comes from.

// Buzzer
#if BUZZER
#include <driver/rmt.h>
const int buzzerPin = 13;
const rmt_channel_t channel = RMT_CHANNEL_2;
#endif

// buzzer
#if BUZZER
void buzzer_setup() {
  rmt_config_t rmt_cfg;
  rmt_cfg.channel = channel;
  rmt_cfg.gpio_num = static_cast<gpio_num_t>(buzzerPin);
  rmt_cfg.clk_div = 250;  // Dies ergibt eine Basis von 320Hz bei 80 MHz APB_CLK_FREQ
  rmt_cfg.mem_block_num = 1;
  rmt_cfg.rmt_mode = RMT_MODE_TX;
  rmt_cfg.tx_config.loop_en = false;
  rmt_cfg.tx_config.carrier_en = false;
  rmt_cfg.tx_config.idle_level = RMT_IDLE_LEVEL_LOW;
  rmt_cfg.tx_config.idle_output_en = true;

  rmt_config(&rmt_cfg);
  rmt_driver_install(channel, 0, 0);
}
#endif

// ALARM TONE 1
// duration high & low only 15 bit width
void Alarm1() {
  const uint32_t duration_long = 32000;  // Beispielwerte: 32000 -> 32000 * (1 / (80000000 / 250 )) s --- 100 ms
  const uint32_t duration_short = 3200;  // 3200 10ms
#if BUZZER
  rmt_item32_t signal[] = {
    { duration_long, 1, duration_long, 1 },  // Erster Piepton 0,2 sek
    { duration_long, 1, duration_long, 1 },  // Zweiter Piepton 0,2 sek
    { duration_long, 1, duration_long, 1 },  // Zweiter Piepton 0,2 sek
    { duration_long, 1, duration_long, 1 },  // Zweiter Piepton 0,2 sek
    { duration_long, 1, duration_long, 1 },  // Zweiter Piepton 0,2 sek
    { duration_long, 0, duration_long, 0 },  // Zweiter Piepton 0 sek
    { duration_long, 0, duration_long, 0 },  // Zweiter Piepton 0 sek
    { duration_long, 1, duration_long, 1 },  // Zweiter Piepton 0,02 sek
    { duration_long, 1, duration_long, 1 },  // Zweiter Piepton 0,02 sek
    //{ duration_high, 1, duration_low, 1 },  // Zweiter Piepton
    //{ duration_high, 0, duration_low, 1 }  // dritter Piepton
    // ... fügen Sie mehr Pieptöne oder Pausen hinzu, wie gewünscht
  };

  //Serial.print("num item: ");
  //Serial.println((int)(sizeof(signal) / sizeof(signal[0])));

  //rmt_write_items(channel, signal, 1, true);
  rmt_write_items(channel, signal, (int)(sizeof(signal) / sizeof(signal[0])), false);
#endif
  //rmt_wait_tx_done(channel, portMAX_DELAY);
}

// ALARM TONE 2
// duration high & low only 15 bit width
void Alarm2() {
  const uint32_t duration_long = 32000;  // Beispielwerte: 32000 -> 32000 * (1 / (80000000 / 250 )) s --- 100 ms
  const uint32_t duration_short = 3200;  // 3200 10ms
#if BUZZER
  rmt_item32_t signal[] = {
    { duration_long, 1, duration_long, 1 },  // Erster Piepton 0,2 sek
    { duration_long, 1, duration_long, 1 },  // Zweiter Piepton 0,2 sek
    { duration_long, 1, duration_long, 1 },  // Zweiter Piepton 0,2 sek
    { duration_long, 1, duration_long, 1 },  // Zweiter Piepton 0,2 sek
    { duration_long, 1, duration_long, 1 },  // Zweiter Piepton 0,2 sek
    { duration_long, 0, duration_long, 0 },  // Zweiter Piepton 0,2 sek
    { duration_long, 0, duration_long, 0 },  // Zweiter Piepton 0,2 sek
    { duration_long, 1, duration_long, 1 },  // Zweiter Piepton 0,02 sek
    { duration_long, 1, duration_long, 1 },  // Zweiter Piepton 0,02 sek
    { duration_long, 1, duration_long, 1 },  // Zweiter Piepton 0,02 sek
    { duration_long, 1, duration_long, 1 },  // Zweiter Piepton 0,02 sek
    { duration_long, 1, duration_long, 1 },  // Zweiter Piepton 0,02 sek
    { duration_long, 0, duration_long, 0 },  // Zweiter Piepton 0 sek
    { duration_long, 0, duration_long, 0 },  // Zweiter Piepton 0,2 sek
    { duration_long, 1, duration_long, 1 },  // Zweiter Piepton 0,02 sek
    { duration_long, 1, duration_long, 1 },  // Zweiter Piepton 0,02 sek
    //{ duration_high, 1, duration_low, 1 },  // Zweiter Piepton
    //{ duration_high, 0, duration_low, 1 }  // dritter Piepton
    // ... fügen Sie mehr Pieptöne oder Pausen hinzu, wie gewünscht
  };

  //Serial.print("num item: ");
  //Serial.println((int)(sizeof(signal) / sizeof(signal[0])));

  //rmt_write_items(channel, signal, 1, true);
  rmt_write_items(channel, signal, (int)(sizeof(signal) / sizeof(signal[0])), false);
#endif
  //rmt_wait_tx_done(channel, portMAX_DELAY);
}

// buzzer end
sirpete83 commented 1 month ago

after a few tests even this approach did not lead to success:

// ALARM TONE 1
// duration high & low only 15 bit width
void Alarm1() {
  const uint32_t duration_long = 32000;  // Beispielwerte: 32000 -> 32000 * (1 / (80000000 / 250 )) s --- 100 ms
  const uint32_t duration_short = 3200;  // 3200 10ms
#if BUZZER
  rmt_item32_t signal[] = {
    { duration_long, 1, duration_long, 1 },  // Erster Piepton 0,2 sek
    { duration_long, 1, duration_long, 1 },  // Zweiter Piepton 0,2 sek
    { duration_long, 1, duration_long, 1 },  // Zweiter Piepton 0,2 sek
    { duration_long, 1, duration_long, 1 },  // Zweiter Piepton 0,2 sek
    { duration_long, 1, duration_long, 1 },  // Zweiter Piepton 0,2 sek
    { duration_long, 0, duration_long, 0 },  // Zweiter Piepton 0 sek
    { duration_long, 0, duration_long, 0 },  // Zweiter Piepton 0 sek
    { duration_long, 1, duration_long, 1 },  // Zweiter Piepton 0,02 sek
    { duration_long, 1, duration_long, 1 },  // Zweiter Piepton 0,02 sek
    //{ duration_high, 1, duration_low, 1 },  // Zweiter Piepton
    //{ duration_high, 0, duration_low, 1 }  // dritter Piepton
    // ... fügen Sie mehr Pieptöne oder Pausen hinzu, wie gewünscht
  };

  //Serial.print("num item: ");
  //Serial.println((int)(sizeof(signal) / sizeof(signal[0])));

  //rmt_write_items(channel, signal, 1, true);
  vTaskSuspend(xTaskGetHandle("SensorTask"));
  rmt_write_items(channel, signal, (int)(sizeof(signal) / sizeof(signal[0])), true);
  rmt_wait_tx_done(channel, portMAX_DELAY);
  vTaskResume(xTaskGetHandle("SensorTask"));
#endif

}
junkfix commented 1 month ago

try something like this so both dont use the rmt at the same time

//addition
volatile uint8_t waitTemp=0;
...
void tempTask(void *pvParameters){
...
    for(;;){
//addition
        waitTemp=1;
//
        ds.request();
        vTaskDelay(750 / portTICK_PERIOD_MS);
        for(byte i = 0; i < MaxDevs; i++){
            uint8_t err = ds.getTemp(addr[i], currTemp[i]);
...
        }
//addition
        waitTemp=0;
}

//
void Alarm1() {
//addition
    while(waitTemp == 1){
        vTaskDelay(100 / portTICK_PERIOD_MS);
    }
//
    const uint32_t duration_long = 32000;
    ...

you can also change the core from 0 to 1 xTaskCreatePinnedToCore(tempTask, "tempTask", 2048, NULL, 1, NULL, 1); // last param for core

sirpete83 commented 1 month ago

I made further attempts. Unfortunately, during my debugging I discovered that the sensor task was not only interfering with my sound generator but also with my OTA update, so some attempts were unsuccessful because I didn't realize that the new firmware hadn't been installed at all. Stupid mistake... but unfortunately I don't have any way of accessing the device serially without a lot of effort... anyway. I tried your suggestion, but in the other direction. If a sound is to be played, the task is completed and then released again. I think a better option should be possible with the RTOS's mutex. But I still need to look into that more. Especially since I also have to turn off the sensor task when an OTA update is started.

void Alarm1() {
  const uint32_t duration_long = 32000;  // Beispielwerte: 32000 -> 32000 * (1 / (80000000 / 250 )) s --- 100 ms
  const uint32_t duration_short = 3200;  // 3200 10ms

#if BUZZER
  buzzer_setup();

  rmt_item32_t signal[] = {
    { duration_long, 1, duration_long, 1 },  // Erster Piepton 0,2 sek
    { duration_long, 1, duration_long, 1 },  // Erster Piepton 0,2 sek
    { duration_long, 1, duration_long, 1 },  // Erster Piepton 0,2 sek
    { duration_long, 1, duration_long, 1 },  // Erster Piepton 0,2 sek
    { duration_long, 1, duration_long, 1 },  // Erster Piepton 0,2 sek -> beep 1 sec
    { duration_long, 0, duration_long, 0 },  // Erste Pause 0,2 sek
    { duration_long, 0, duration_long, 0 },  // Erste Pause 0,2 sek - pause 0,4 sec
    { duration_long, 1, duration_long, 1 },  // Zweiter Piepton 0,2 sek
    { duration_long, 1, duration_long, 1 },  // Zweiter Piepton 0,2 sek - beep 0,4 sec

  };

  //rmt_write_items(channel, signal, 1, true);
  new_temp = 2;
  while (new_temp != 3) {
    vTaskDelay(pdMS_TO_TICKS(500));
  }
  telnet.println("Tone ");
  vTaskDelay(pdMS_TO_TICKS(15));
  rmt_write_items(channel, signal, (int)(sizeof(signal) / sizeof(signal[0])), true);
  rmt_wait_tx_done(channel, portMAX_DELAY);
  telnet.println("Tone Done");
  new_temp = 0; // request new values to transmit
  vTaskResume(xTaskGetHandle("SensorTask"));  // unhalt sensortask

#endif
}

and in the sensor task:

void TaskReadSensors(void* pvParameters)  // This is a task.
{
  (void)pvParameters;
  for (;;)  // A Task shall never return or exit.
  {
    TickType_t xLastWakeTime;
    // Initialise the xLastWakeTime variable with the current time.
    xLastWakeTime = xTaskGetTickCount();
    //telnet.print("\033[H\033[J");
    //telnet.println(String(xLastWakeTime));
    if (new_temp == 0) {
      //telnet.println("get_sensors task");

#if DS1820_RMT
      ds.request();
      vTaskDelay(750 / portTICK_PERIOD_MS);

      for (byte i = 0; i < MaxDevs; i++) {
        uint8_t err = ds.getTemp(addr[i], currTemp[i]);
        if (err) {
          const char* errt[] = { "", "CRC", "BAD", "DC", "DRV" };
          telnet.print(i);
          telnet.print(": ");
          telnet.println(errt[err]);
        } else {
          new_temp = 1;
          tempC[i] = currTemp[i];
          telnet.print(i);
          telnet.print(": ");
          telnet.println(currTemp[i]);
        }
      }
#endif

      vTaskDelay(pdMS_TO_TICKS(1480));
    }

// halt this task for ota and buzzer
    if (new_temp == 2) {
      new_temp = 3;
      vTaskSuspend(NULL);
    }

    vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(sensor_time_ms));
    //vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(4000));
  }
}
sirpete83 commented 1 month ago

I still have the Problem that it does not work as i think i should. Using this Module should not block the CPU but if do not wait until tx is finished nothing helt rather mutex or the own interruption of requesting the sensors

Documentation says rmt is threadsafe/task safe by Design. Clock source is the same... Maybe with the New idf 5.x Port to arduino there will be some fixes?

junkfix commented 1 month ago

Please try new version