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

ESP32 S2 crash in static void IRAM_ATTR uart_intr_handle() #55

Open
chrisDupuis opened this issue May 22, 2024 · 23 comments
Open

ESP32 S2 crash in static void IRAM_ATTR uart_intr_handle() #55

chrisDupuis opened this issue May 22, 2024 · 23 comments

Comments

@chrisDupuis
Copy link

Crash with ESP32 S2 mini.

(Code is running on ESP32)

Someone have test on ESP32 S2 ?
Any idea how to solve that ?

@ericlangel
Copy link
Collaborator

i dont have a S2 for testing

interesting that it is running on ESP32

which ESP32 Hardware Core Version?
can u use the Exception decoder?

@chrisDupuis
Copy link
Author

chrisDupuis commented May 22, 2024

S2 Mini V1.0.0,

Hailege 3pcs ESP32 S2 Mini WiFi Development Board WIFI IOT Wireless Board Based on ESP32-S2FN4R2 ESP32-S2 4MB Flash Type-C MicroPython Arduino Compatible

I have no exception shown,
only constantly rebooting...

@ericlangel
Copy link
Collaborator

I need the version of your ESP32 arduino core version
is it already 3.0.0?
or 2.0.16?
or?

@chrisDupuis
Copy link
Author

I use 2.0.16
In 3.0.0 I can't compile, error...

@ericlangel
Copy link
Collaborator

did you had a look at #44 ?

there are several reasons for crashing. It's hard to get the right one without exception decoder
i could try to get a S2 Board, but i need some time to rework the code

there are several known issues, but i had no time for fix

@chrisDupuis
Copy link
Author

Yes I use this topic and done some test since 3 days.

If I remove
ESP_ERROR_CHECK(uart_isr_register(uart_num, uart_intr_handle, NULL, ESP_INTR_FLAG_IRAM, 0 /*handle_console*/));
No crash.

If I return in ISR uart, then crash.

static void IRAM_ATTR uart_intr_handle(void *arg)
{
uint16_t status = UART1.int_st.val; // read UART interrupt Status
// status = UART1.int_st.val; // read UART interrupt Status
uart_clear_intr_status(uart_num, UART_RXFIFO_FULL_INT_CLR | UART_RXFIFO_TOUT_INT_CLR);
uart_clear_intr_status(uart_num, status);

return;
}

@ericlangel
Copy link
Collaborator

ESP_ERROR_CHECK(uart_isr_register(uart_num, uart_intr_handle, NULL, ESP_INTR_FLAG_IRAM, 0 /handle_console/));

this call register the function uart_intr_handle to the Interrupt
without this, the handler is never called so of course there is no Crash

you could try to register the function without ESP_INTR_FLAG_IRAM

@chrisDupuis
Copy link
Author

Same crash without ESP_INTR_FLAG_IRAM.

I try to have very simple uart_intr_handle with minimum code,
in ordre to not have crash/reboot.

@chrisDupuis
Copy link
Author

chrisDupuis commented May 22, 2024

What about that for minimum code

static void IRAM_ATTR uart_intr_handle(void *arg)
{
  uart_clear_intr_status(uart_num, UART_RXFIFO_FULL_INT_CLR | UART_RXFIFO_TOUT_INT_CLR);
  return;
}

@chrisDupuis
Copy link
Author

One more, info,
If no SBUS2 signal, no crash.

@ericlangel
Copy link
Collaborator

Ok lets try to work it out.

  • No SBUS Signal no crash. Thats right. without SBUS signal the UART Interrupt is never executed

please uncomment the following lines/functions one by one and report back

  • disable_receiving(); line321
  • start_transmit_sequencer(((rxbuf[24]&0x30) >> 4)); line 330
  • pinMatrixOutDetach(tx_pin,false,true); line265

the first 2 are working with the Timer, and i'am sure it is more or less a Timer Problem, but who knows

@chrisDupuis
Copy link
Author

Test comment this line:

disable_receiving(); line321 => reboot
start_transmit_sequencer(((rxbuf[24]&0x30) >> 4)); line 330 => reboot
pinMatrixOutDetach(tx_pin,false,true); line265 => reboot

@chrisDupuis
Copy link
Author

On more info,
with the same module and pin assignment, I have test with iBus telemetry, and it s running ok
https://github.com/bmellink/IBusBM

So for me the hardware, and wire is ok.

@chrisDupuis
Copy link
Author

chrisDupuis commented May 23, 2024

I add a rtc_get_reset_reason, print_reset_reason, and the cause is SW_RESET, RESET_REASON = 3

@ericlangel
Copy link
Collaborator

Test comment this line:

disable_receiving(); line321 => reboot start_transmit_sequencer(((rxbuf[24]&0x30) >> 4)); line 330 => reboot pinMatrixOutDetach(tx_pin,false,true); line265 => reboot

And all 3 disabled together?

@ericlangel
Copy link
Collaborator

here is the answer: Link

in the last comment

could you try to change:
rxbuf[buffer_index] = UART1.fifo.rw_byte; // read all bytes

to

rxbuf[buffer_index] = READ_PERI_REG(UART_FIFO_AHB_REG(1)); // read all bytes

But there seems to be a bigger issue with the UART Periph on S2. So maybe its not crashing any more but UART is not read correctly

@chrisDupuis
Copy link
Author

all 3 together, same, reboot

@chrisDupuis
Copy link
Author

chrisDupuis commented May 23, 2024

OK, the problem is here:

while (rx_fifo_len)
  {
    // rxbuf[buffer_index] = UART1.fifo.rw_byte; // read all bytes
    //rxbuf[buffer_index] = UART1.ahb_fifo.rw_byte; // read all bytes
    rxbuf[buffer_index] = READ_PERI_REG(UART_FIFO_AHB_REG(1));

    rx_fifo_len--;
    buffer_index++;
    // Serial.print(rxbuf[buffer_index],HEX);
    // Serial.print(" ");
    /*if(rxbuf[0] == 0x0f){						// Start of SBUS(2) Frame
      buffer_index++;
    }
    else{										// Telemetry Slot?
    //digitalWrite(16,HIGH);
    buffer_index++;
    }*/
  }

OK Running with that and fix use of TIMER_1

@ericlangel
Copy link
Collaborator

ericlangel commented May 24, 2024

Nice to hear.

What did u change?
just READ_PERI_REG(UART_FIFO_AHB_REG(1)) ?

is it still working on esp32 (without S2)?
And SBUS2 is working, too?

@chrisDupuis
Copy link
Author

Here the code for ESP32 and ESP32_S2

/*
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#if defined(ESP32)
#include "SBUS_usart.h"
#include "esp32-hal.h"
#include "esp32-hal-uart.h"

// #include "freertos/FreeRTOS.h"
// #include "freertos/event_groups.h"
// #include "esp_task.h"
// #include "esp_task_wdt.h"
// #include "freertos/queue.h"
#include "driver/uart.h"
#include <soc/uart_reg.h>
#include <driver/timer.h>
#include <soc/uart_struct.h>
#include <soc/timer_group_struct.h>

#include <stdarg.h>
#include <stdlib.h>
#include <string.h>

#define SLOT_DATA_LENGTH 3
#define NUMBER_OF_FRAMES 4
#define NUMBER_OF_SLOT 32
#define NUMBER_OF_SLOT_IN_FRAME 8
#define SBUS_FRAME_SIZE 25

#if CONFIG_IDF_TARGET_ESP32
#define SBUS2_UART_RX_PIN (GPIO_NUM_25)
#define SBUS2_UART_TX_PIN (GPIO_NUM_26)
#elif CONFIG_IDF_TARGET_ESP32S2
#define SBUS2_UART_RX_PIN (16)
#define SBUS2_UART_TX_PIN (17)
#endif

#define UART_RXBUFSIZE 30

#define SLOT_TIME 660  // 660 ms
#define WAIT_TIME 2000 // 2000 ms

#define RX_BUF_SIZE 1024 // we dont need more space in buffer

bool DemoMode = false;

// 32 Slots for telemetrie Data
uint8_t Slot_ID[NUMBER_OF_SLOT] = {0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
                                   0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
                                   0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
                                   0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB};

char sbus_frame[25] = {0x0F, 0xA0, 0xA3, 0x20, 0x56, 0x2C, 0x08, 0x16, 0x50, 0x03, 0x10, 0x80, 0x00, 0x04, 0x20, 0x00, 0x01, 0x08, 0x07, 0xC8, 0x03, 0x10, 0x80, 0x02, 0x04};

// channels for connected servos at the SBUS
uint16_t channels[NUMBER_OF_CHANNELS];

static volatile uint8_t rxbuf[UART_RXBUFSIZE];
static volatile uint8_t sbusData[UART_RXBUFSIZE];
static volatile uint8_t telemetryData[256];
static volatile bool frame_ready = false;
static volatile bool telemetry_ready = false;
static volatile bool sbus_ready = false;
static volatile uint8_t gl_current_frame = 0;
static volatile uint16_t uart_lost_frame = 0;
static volatile uint8_t FER_count = 0;
static volatile uint8_t FER_buf[100];

static volatile uint8_t buffer_index = 0;

static volatile uint8_t tx_pin;
uart_port_t uart_num;

typedef enum
{
  EMPTY = 0,
  TRANSMITTING,
  AVAILABLE
} SLOT_DATA_STATUS;

typedef struct
{
  bool data_status;
  uint8_t data[SLOT_DATA_LENGTH];
} SLOT_RAW_DATA;

static volatile int8_t previousFrame = 0;
static volatile uint32_t frameCounter = 0;

static volatile uint8_t sequence_count = 0; // first sequence step delay will be filled in when the transmit sequence is enabled

static volatile bool transmit = false;

volatile SLOT_DATA_STATUS transmit_data_per_slot_status[NUMBER_OF_SLOT];
volatile uint8_t transmit_data_per_slot_data[NUMBER_OF_SLOT][SLOT_DATA_LENGTH];

void initialize_slot_status();
void enable_receiving();
void disable_receiving();
void start_transmit_sequencer(uint8_t frame_number);

void SBUS2_get_all_servo_data();

/*******************************************************************************
 * ESP32 is able to invert the RX and TX Lines itself, so we dont need an external inverter
 * Also the HardwareSerial Library has interup driven input/output buffers and we dont need
 * to implent this on our own.
 * I implement the receiver part as an extra task, to avoid looping in main loop.
 * The transmitter is also implemented as a task to be able to follow the requird timings.
 *
 */

uart_config_t uart_config = {
    .baud_rate = 100000,
    .data_bits = UART_DATA_8_BITS,
    .parity = UART_PARITY_EVEN,
    .stop_bits = UART_STOP_BITS_2,
    .flow_ctrl = UART_HW_FLOWCTRL_DISABLE};

timer_config_t timer_config = {
    .alarm_en = TIMER_ALARM_EN,         // Alarm Enable
    .counter_en = TIMER_PAUSE,          // If the counter is enabled it will start incrementing / decrementing immediately after calling timer_init()
    .intr_type = TIMER_INTR_LEVEL,      // Is interrupt is triggered on timer’s alarm (timer_intr_mode_t)
    .counter_dir = TIMER_COUNT_UP,      // Does counter increment or decrement (timer_count_dir_t)
    .auto_reload = TIMER_AUTORELOAD_EN, // If counter should auto_reload a specific initial value on the timer’s alarm, or continue incrementing or decrementing.
    .divider = 80                       // Divisor of the incoming 80 MHz (12.5nS) APB_CLK clock. E.g. 80 = 1uS per timer tick
};

/* ISR to transmit the frame */
static void IRAM_ATTR ISR_transmit_frame(void *arg);
static void IRAM_ATTR uart_intr_handle(void *arg);

//*****************************************************************************
//
void SBUS2_enable_simulation()
{
  log_i("[SBUS2] Demo Mode enabled");
  DemoMode = true;
}

void SBUS2_disable_simulation()
{
  log_i("[SBUS2] Demo Mode disabled");
  DemoMode = false;
}

void SBUS2_uart_setup()
{
  SBUS2_uart_setup(SBUS2_UART_RX_PIN, SBUS2_UART_TX_PIN, UART_NUM_1);
}

void SBUS2_uart_setup(int rx, int tx)
{
  SBUS2_uart_setup(rx, tx, UART_NUM_1);
}

void SBUS2_uart_setup(int rx, int tx, int uart)
{
  tx_pin = tx;
  uart_num = (uart_port_t)uart;
  ESP_ERROR_CHECK(uart_param_config(uart_num, &uart_config));
#if (ESP_ARDUINO_VERSION_MAJOR == 2)
  ESP_ERROR_CHECK(uart_set_line_inverse(uart_num, UART_SIGNAL_TXD_INV | UART_SIGNAL_RXD_INV)); // V2.0.0
#else
  ESP_ERROR_CHECK(uart_set_line_inverse(uart_num, UART_INVERSE_RXD | UART_INVERSE_TXD)); // V1.6.0
#endif
  ESP_ERROR_CHECK(uart_set_pin(uart_num, tx, rx, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
  gpio_set_pull_mode((gpio_num_t)rx, GPIO_PULLDOWN_ONLY);
  gpio_pulldown_en((gpio_num_t)rx);
  ESP_ERROR_CHECK(uart_driver_install(uart_num, RX_BUF_SIZE, 0, 0, NULL, 0));
  ESP_ERROR_CHECK(uart_isr_free(uart_num));
  ESP_ERROR_CHECK(uart_isr_register(uart_num, uart_intr_handle, NULL, ESP_INTR_FLAG_IRAM, 0 /*handle_console*/));
  ESP_ERROR_CHECK(uart_enable_rx_intr(uart_num));

  // setup transmitter ISR
  timer_init(TIMER_GROUP_0, TIMER_1, &timer_config);
  timer_set_counter_value(TIMER_GROUP_0, TIMER_1, 0);
  timer_set_alarm_value(TIMER_GROUP_0, TIMER_1, SLOT_TIME);
  timer_enable_intr(TIMER_GROUP_0, TIMER_1);
  timer_isr_register(TIMER_GROUP_0, TIMER_1, &ISR_transmit_frame, NULL, 0, 0 /*&s_timer_handle*/);
  timer_set_alarm(TIMER_GROUP_0, TIMER_1, TIMER_ALARM_EN);

  uart_flush(uart_num);

  uart_intr_config_t uart_intr;
  uart_intr.intr_enable_mask = UART_RXFIFO_FULL_INT_ENA_M | UART_RXFIFO_TOUT_INT_ENA_M;
  uart_intr.rxfifo_full_thresh = 26;
  uart_intr.rx_timeout_thresh = 2;
  uart_intr.txfifo_empty_intr_thresh = 10;
  uart_intr_config(uart_num, &uart_intr);

  initialize_slot_status();

  enable_receiving();

  if (DemoMode)
  { // Nur wenn demo Mode
    uart_write_bytes(uart_num, sbus_frame, SBUS_FRAME_SIZE);
    sbus_frame[24] += 0x10;
  }
  else
  {
    pinMatrixOutDetach(tx_pin, false, true);
  }
}

void initialize_slot_status()
{
  for (uint8_t i = 0; i < NUMBER_OF_SLOT; i++)
  {
    transmit_data_per_slot_status[i] = EMPTY;
  }
}

void disable_receiving()
{
  sequence_count = 0;

  timer_set_alarm(TIMER_GROUP_0, TIMER_1, TIMER_ALARM_DIS);
  timer_pause(TIMER_GROUP_0, TIMER_1);

  timer_set_alarm_value(TIMER_GROUP_0, TIMER_1, WAIT_TIME); // RX Interrupt with delay of 700µs -> 700µs + 1300µs = 2ms
  timer_set_counter_value(TIMER_GROUP_0, TIMER_1, 0);
  timer_set_alarm(TIMER_GROUP_0, TIMER_1, TIMER_ALARM_EN);
  timer_start(TIMER_GROUP_0, TIMER_1);
}

void enable_receiving()
{
  // disable transmitter ISR
  /*timer_set_alarm(TIMER_GROUP_0,TIMER_1,TIMER_ALARM_DIS);
  timer_pause(TIMER_GROUP_0,TIMER_1);
  timer_set_counter_value(TIMER_GROUP_0,TIMER_1,0);*/

  timer_set_counter_value(TIMER_GROUP_0, TIMER_1, 0);
  timer_set_alarm_value(TIMER_GROUP_0, TIMER_1, 15000);
  timer_set_alarm(TIMER_GROUP_0, TIMER_1, TIMER_ALARM_EN);

  // flush input buffer first, to avoid getting old SBUS-Frames
  // uart_flush(uart_num);
  buffer_index = 0;
}

inline void IncreaseTimer(int8_t frameNumber)
{
  int8_t temp = (frameNumber - previousFrame) % NUMBER_OF_FRAMES;
  if (temp <= 0)
    temp += NUMBER_OF_FRAMES;
  if (temp > 1)
    uart_lost_frame++;
  frameCounter += temp;
  previousFrame = frameNumber;
}

static void IRAM_ATTR uart_intr_handle(void *arg)
{
  // digitalWrite(18,HIGH);
  // CHD pinMatrixOutDetach(tx_pin, false, true);
  uart_clear_intr_status(uart_num, UART_RXFIFO_FULL_INT_CLR | UART_RXFIFO_TOUT_INT_CLR);
  uint16_t rx_fifo_len, status;
  status = UART1.int_st.val;             // read UART interrupt Status
  rx_fifo_len = UART1.status.rxfifo_cnt; // read number of bytes in UART buffer
  /*Serial.print("Fifo len = ");
  Serial.println(rx_fifo_len);*/
  if (rx_fifo_len == 0)
  {
    return;
  }
  else if (rx_fifo_len == 25)
  {
  }
  else if (rx_fifo_len == 3)
  {
  }
  else
  {
    // digitalWrite(18,HIGH);
    /*Serial.print("Error! -> rx_fifo_len = ");
    Serial.print(rx_fifo_len);
    Serial.print(" Value = ");
    for(uint8_t i=0; i<=rx_fifo_len;i++){
    Serial.print(rxbuf[i], HEX);
    Serial.print(", ");
    }
    Serial.println(" [HEX]");*/
    uart_flush(uart_num);
    uart_clear_intr_status(uart_num, UART_RXFIFO_FULL_INT_CLR | UART_RXFIFO_TOUT_INT_CLR);
    log_i("[SBUS2] Wrong Frame length\l\n");
    return;
  }
  // digitalWrite(18,HIGH);

  while (rx_fifo_len)
  {
#if CONFIG_IDF_TARGET_ESP32
    rxbuf[buffer_index] = UART1.fifo.rw_byte; // read all bytes
#elif CONFIG_IDF_TARGET_ESP32S2
    rxbuf[buffer_index] = READ_PERI_REG(UART_FIFO_AHB_REG(1));
#endif
    rx_fifo_len--;
    buffer_index++;
    // Serial.print(rxbuf[buffer_index],HEX);
    // Serial.print(" ");
    /*if(rxbuf[0] == 0x0f){						// Start of SBUS(2) Frame
      buffer_index++;
    }
    else{										// Telemetry Slot?
    //digitalWrite(16,HIGH);
    buffer_index++;
    }*/
  }
  if ((buffer_index == SBUS_FRAME_SIZE) && (rxbuf[0] == 0x0f)) // SBUS Frame
  {
    // digitalWrite(18,HIGH);
    telemetry_ready = false;
    sbus_ready = false;
    frame_ready = true;
    for (uint8_t i = 0; i < UART_RXBUFSIZE; i++)
    {
      sbusData[i] = rxbuf[i];
    }
    disable_receiving();
    IncreaseTimer((rxbuf[24] & 0x30) >> 4);
    buffer_index = 0;
    // Serial.println();
    if ((rxbuf[24] & 0x0f) == 0x04)
    { // Valid SBUS2 Frame
      // digitalWrite(18,HIGH);
      telemetry_ready = true;
      sbus_ready = true;
      SBUS2_get_all_servo_data();
      start_transmit_sequencer(((rxbuf[24] & 0x30) >> 4)); // frame number needed to select correct telemetry slot
    }
    else if ((rxbuf[24] & 0x0f) == 0x00)
    { // Just SBUS Frame (without Telemetry)
      telemetry_ready = false;
      sbus_ready = true;
      SBUS2_get_all_servo_data();
    }
    else
    { // Something else -> Error
      telemetry_ready = false;
      sbus_ready = false;
      uart_flush(uart_num);
      uart_clear_intr_status(uart_num, UART_RXFIFO_FULL_INT_CLR | UART_RXFIFO_TOUT_INT_CLR);
      log_i("[SBUS2]Invalid Frame End Byte");
    }
    // pinMatrixOutDetach(tx_pin,false,true);
  }
  else if (buffer_index == SBUS_FRAME_SIZE)
  {
    uart_flush(uart_num);
    uart_clear_intr_status(uart_num, UART_RXFIFO_FULL_INT_CLR | UART_RXFIFO_TOUT_INT_CLR);
    log_i("[SBUS2] Invalid Frame Start Byte");
  }
  else if ((buffer_index == SLOT_DATA_LENGTH) && ((((rxbuf[0] & 0x0f) == 0x03) || (rxbuf[0] & 0x0f) == 0x0B))) // Telemetry Slot
  {
    // digitalWrite(18,HIGH);
    uint8_t temp = rxbuf[0];
    telemetryData[temp] = rxbuf[0];
    telemetryData[temp + 1] = rxbuf[1];
    telemetryData[temp + 2] = rxbuf[2];
    buffer_index = 0;
    // pinMatrixOutDetach(tx_pin,false,true);
    // digitalWrite(18,LOW);
  }
  else if (buffer_index == SLOT_DATA_LENGTH)
  { // Something went wrong
    uart_flush(uart_num);
    uart_clear_intr_status(uart_num, UART_RXFIFO_FULL_INT_CLR | UART_RXFIFO_TOUT_INT_CLR);
    log_i("[SBUS2] Invalid Slot ID");
  }
  //}
  // digitalWrite(18,LOW);
  // after reading bytes from buffer clear UART interrupt status
  // uart_flush(uart_num);
  uart_clear_intr_status(uart_num, UART_RXFIFO_FULL_INT_CLR | UART_RXFIFO_TOUT_INT_CLR);
}

/****************************************************************
 * transmit_frame
 *
 * Implemented as an ISR to fit the strict timing requirements
 * Slot 1 has to be transmitted 2ms after receiving the SBUS2 Frame
 * Slot 2-8 has to be transmitted every 660 mirco seconds
 * Each Slot needs about 320 mircoseconds to be transmitted via uart
 * The delay between the Slots must not exceed 400 mirco seconds
 *
 ****************************************************************/

static void IRAM_ATTR ISR_transmit_frame(void *arg)
{
#if CONFIG_IDF_TARGET_ESP32
  TIMERG0.int_clr_timers.t1 = 1;
  TIMERG0.hw_timer[1].config.alarm_en = 1;
#elif CONFIG_IDF_TARGET_ESP32S2
  timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, TIMER_1);
  TIMERG0.hw_timer[0].config.tx_alarm_en = 1;
#endif
  digitalWrite(18, HIGH);
  pinMatrixOutDetach(tx_pin, false, true);
  if (sequence_count < 8) // transmit slots
  {
    uint8_t actual_slot = (sequence_count) + (gl_current_frame * NUMBER_OF_SLOT_IN_FRAME);
    // if data available in slot then send it
    if (transmit_data_per_slot_status[actual_slot] == AVAILABLE)
    {
      // digitalWrite(18,HIGH);
      pinMatrixOutAttach(tx_pin, U1TXD_OUT_IDX, false, false);
      char buffer[SLOT_DATA_LENGTH];
      memcpy(buffer, (const void *)transmit_data_per_slot_data[actual_slot], SLOT_DATA_LENGTH);
      transmit_data_per_slot_status[actual_slot] = TRANSMITTING;
      // send the whole slot
      uart_write_bytes(uart_num, buffer, SLOT_DATA_LENGTH);
      transmit_data_per_slot_status[actual_slot] = EMPTY;
      // digitalWrite(18,LOW);
    }
    if (sequence_count == 7)
    {
      timer_set_counter_value(TIMER_GROUP_0, TIMER_1, 0);
      timer_set_alarm_value(TIMER_GROUP_0, TIMER_1, 5150);
      // timer_set_counter_value(TIMER_GROUP_0, TIMER_1, 0);
      timer_set_alarm(TIMER_GROUP_0, TIMER_1, TIMER_ALARM_EN);
    }
    else
    {
      timer_set_counter_value(TIMER_GROUP_0, TIMER_1, 0);
      timer_set_alarm_value(TIMER_GROUP_0, TIMER_1, SLOT_TIME);
      // timer_set_counter_value(TIMER_GROUP_0, TIMER_1, 0);
      timer_set_alarm(TIMER_GROUP_0, TIMER_1, TIMER_ALARM_EN);
    }
  }
  /*else if(sequence_count = 8){
  timer_set_counter_value(TIMER_GROUP_0, TIMER_1, 0);
    timer_set_alarm_value(TIMER_GROUP_0, TIMER_1, 4500);
  //timer_set_counter_value(TIMER_GROUP_0, TIMER_1, 0);
    timer_set_alarm(TIMER_GROUP_0,TIMER_1,TIMER_ALARM_EN);
  }*/

  else
  {
    // digitalWrite(18,HIGH);	// dummy for sending SBUS2 Frame
    if (DemoMode)
    {
      pinMatrixOutAttach(tx_pin, U1TXD_OUT_IDX, false, false);
      uart_write_bytes(uart_num, sbus_frame, SBUS_FRAME_SIZE);
      sbus_frame[24] += 0x10;
      if (sbus_frame[24] > 0x34)
      {
        sbus_frame[24] = 0x04;
      }
    }
    else
    {
      // pinMatrixOutDetach(tx_pin,false,true);
    }

    buffer_index = 0;
    transmit = false;
    // telemetry_ready = false;
    sequence_count = 0;

    enable_receiving();
  }
  // digitalWrite(18,LOW);
  sequence_count++;
}

void start_transmit_sequencer(uint8_t frame_number)
{
  gl_current_frame = frame_number;
  // we dont need more frames to be received, lets handle this one first
  disable_receiving();
}

void SBUS2_transmit_telemetry_data(uint8_t slot, uint8_t data[SLOT_DATA_LENGTH])
{
  if (transmit_data_per_slot_status[slot] != TRANSMITTING)
  {

    transmit_data_per_slot_data[slot][0] = Slot_ID[slot];
    transmit_data_per_slot_data[slot][1] = data[1];
    transmit_data_per_slot_data[slot][2] = data[2];

    transmit_data_per_slot_status[slot] = AVAILABLE;
  }
}

void SBUS2_get_all_servo_data()
{
  channels[0] = ((sbusData[1] | sbusData[2] << 8) & 0x07FF);
  channels[1] = ((sbusData[2] >> 3 | sbusData[3] << 5) & 0x07FF);
  channels[2] = ((sbusData[3] >> 6 | sbusData[4] << 2 | sbusData[5] << 10) & 0x07FF);
  channels[3] = ((sbusData[5] >> 1 | sbusData[6] << 7) & 0x07FF);
  channels[4] = ((sbusData[6] >> 4 | sbusData[7] << 4) & 0x07FF);
  channels[5] = ((sbusData[7] >> 7 | sbusData[8] << 1 | sbusData[9] << 9) & 0x07FF);
  channels[6] = ((sbusData[9] >> 2 | sbusData[10] << 6) & 0x07FF);
  channels[7] = ((sbusData[10] >> 5 | sbusData[11] << 3) & 0x07FF);
  channels[8] = ((sbusData[12] | sbusData[13] << 8) & 0x07FF);
  channels[9] = ((sbusData[13] >> 3 | sbusData[14] << 5) & 0x07FF);
  channels[10] = ((sbusData[14] >> 6 | sbusData[15] << 2 | sbusData[16] << 10) & 0x07FF);
  channels[11] = ((sbusData[16] >> 1 | sbusData[17] << 7) & 0x07FF);
  channels[12] = ((sbusData[17] >> 4 | sbusData[18] << 4) & 0x07FF);
  channels[13] = ((sbusData[18] >> 7 | sbusData[19] << 1 | sbusData[20] << 9) & 0x07FF);
  channels[14] = ((sbusData[20] >> 2 | sbusData[21] << 6) & 0x07FF);
  channels[15] = ((sbusData[21] >> 5 | sbusData[22] << 3) & 0x07FF);

  // DigiChannel 1
  if (sbusData[23] & (1 << 0))
  {
    channels[16] = 1;
  }
  else
  {
    channels[16] = 0;
  }
  // DigiChannel 2
  if (sbusData[23] & (1 << 1))
  {
    channels[17] = 1;
  }
  else
  {
    channels[17] = 0;
  }
  if (sbusData[23] & 0x04)
  {
    FER_buf[FER_count] = 1;
    FER_count++;
    if (FER_count > 99)
    {
      FER_count = 0;
    }
  }
  else
  {
    FER_buf[FER_count] = 0;
    FER_count++;
    if (FER_count > 99)
    {
      FER_count = 0;
    }
  }
}

void SBUS2_get_status(uint16_t *uart_dropped_frame, bool *transmision_dropt_frame, bool *failsave)
{
  if (frameCounter < 60)
  {
    uart_lost_frame = 0;
  }
  *uart_dropped_frame = uart_lost_frame;
  uart_lost_frame = 0;
  *transmision_dropt_frame = sbusData[23] & 0x04 ? true : false;
  *failsave = sbusData[23] & 0x08 ? true : false;
}

int16_t SBUS2_get_servo_data(uint8_t channel)
{
  if (channel < NUMBER_OF_CHANNELS)
  {
    return channels[channel];
  }
  else
  {
    return -1;
  }
}

bool SBUS_Ready()
{
  if (sbus_ready) // Checking sbus_ready Flag
  {
    sbus_ready = false;
    return true;
  }
  else
  {
    return false;
  }
}

bool SBUS2_Ready()
{
  // Serial.println("test");
  if (telemetry_ready)
  {
    telemetry_ready = false;
    // digitalWrite(18,LOW);
    return true;
  }
  else
  {
    return false;
  }
}

bool SBUS_Ready(bool reset)
{
  if (sbus_ready) // Checking sbus_ready Flag
  {
    if (reset)
    {
      sbus_ready = false;
    }
    return true;
  }
  else
  {
    return false;
  }
}

bool SBUS2_Ready(bool reset)
{
  if (telemetry_ready)
  {
    if (reset)
    {
      telemetry_ready = false;
    }
    return true;
  }
  else
  {
    return false;
  }
}

uint8_t SBUS_get_FER()
{
  uint8_t fer = 0;
  for (uint8_t i = 0; i < 100; i++)
  {
    if (FER_buf[i] == 1)
    {
      fer++;
    }
  }
  return fer;
}

uint8_t SBUS_get_RSSI()
{
  uint8_t rssi = SBUS_get_FER();
  rssi = 100 - rssi;
  return rssi;
}

void SBUS2_print_Raw()
{
  for (uint16_t i = 0; i < 256; i++)
  {
    Serial.print(i, HEX);
    Serial.print(" ");
  }
  Serial.println();
  for (uint16_t i = 0; i < 256; i++)
  {
    Serial.print(telemetryData[i], HEX);
    Serial.print(" ");
  }
  Serial.println();
}

bool SBUS2_get_Slot(uint8_t slot, uint8_t *lowbyte, uint8_t *highbyte)
{
  uint8_t slotid = Slot_ID[slot];
  if (telemetryData[slotid] == slotid)
  {
    // Sensordaten vorhanden
    *lowbyte = telemetryData[slotid + 1];
    *highbyte = telemetryData[slotid + 2];
    telemetryData[slotid] = 0;
    telemetryData[slotid + 1] = 0;
    telemetryData[slotid + 2] = 0;
    return true;
  }
  else
  {
    // Keine Sensordaten vorhanden
    *lowbyte = 0;
    *highbyte = 0;
    return false;
  }
}

void SBUS_disable()
{
  uart_disable_rx_intr(uart_num);
  timer_set_alarm(TIMER_GROUP_0, TIMER_1, TIMER_ALARM_DIS);
}

void SBUS_enable()
{
  uart_enable_rx_intr(uart_num);
  initialize_slot_status();
  enable_receiving();
}

void SBUS2_disable()
{
  SBUS_disable();
}

void SBUS2_enable()
{
  SBUS_enable();
}
#endif // ESP32

@chrisDupuis
Copy link
Author

Fixed

@ericlangel
Copy link
Collaborator

OK, i have some questions:

u used PIN16/17 on the S2 -> why? are 25/26 not working?

and u changed:

#if CONFIG_IDF_TARGET_ESP32
  TIMERG0.int_clr_timers.t1 = 1;
  TIMERG0.hw_timer[1].config.alarm_en = 1;
#elif CONFIG_IDF_TARGET_ESP32S2
  timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, TIMER_1);
  TIMERG0.hw_timer[0].config.tx_alarm_en = 1;
#endif

TIMERG0.hw_timer[0].config.tx_alarm_en = 1; -> seems wrong to me
should it beTIMERG0.hw_timer[1].config.tx_alarm_en = 1;?

@ericlangel ericlangel reopened this May 27, 2024
@chrisDupuis
Copy link
Author

I use 25/26 because I use an ESP32 S2 Mini Lolin, and no 25/26 pin.
and
You re right, it s a mistake, it must be:
TIMERG0.hw_timer[1].config.tx_alarm_en = 1;

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

2 participants