1+1 = 3 ?! Ringbuffer variables go crazy

Gregor
Posts: 3
Joined: Fri Apr 30, 2021 2:50 am

1+1 = 3 ?! Ringbuffer variables go crazy

Postby Gregor » Sun May 02, 2021 2:28 am

Hi

I have a really strange problem with a program that sends espnow packets. I am using a ringbuffer to send the packets. After a while the ringbuffer variables go out of control. The ring size, begin and end dont match anymore.
I then added a second var for the ring size, that makes the same as the original one. Sometimes those two vars dont have the same value after a while, there is an increasing or decreasing shift between those???!!!
Can someone help me with whats going on here? I'm out of ideas, that doesnt make any sense.

thanks, Gregor

essentiel code parts, whole file is attached:

Code: Select all

typedef
  struct  { 
   uint8_t PosTag;
   uint8_t PosTag2; 
   uint8_t PosTag3;
   uint8_t PosTag4;  
  }
TBuffer;

typedef union {
  struct  { 
   uint8_t PosTag;
   uint8_t PosTag2; 
   uint8_t PosTag3;
   uint8_t PosTag4;  
   int16_t samples[Frame_Size / 2];
  };
  uint8_t Data[Frame_Size+4];
}TBufferEntry;

TBufferEntry  DATA;
  
const int     RB_Size  = 32;
TBuffer       RingBuffer[RB_Size];    // buffer for incoming packets
volatile uint8_t       RingBegin  = 0;
volatile uint8_t       RingEnd  = 0;
volatile int8_t        RingSize  = 0;

uint16_t SampleLR[4];
int16_t  Buffer[16];
int      BufferCount = 0;
uint8_t  PacketCount  = 0;
volatile bool sent = true;
volatile bool CB = false;

uint8_t       LastPos;
volatile int8_t  PCount;

Code: Select all

void reader(void *pvParameters) {
  size_t bytes_read;
  int j = 0;

  while(1){ 
    for (j = 0; j < (Frame_Size / 2);) {
      err = i2s_read(I2S_NUM_0, &Buffer, sizeof(Buffer), &bytes_read, portMAX_DELAY);
 
      if (bytes_read == sizeof(Buffer)) {
        for (int i = 0; i < 16; i+=2) {
          DATA.samples[j] = Buffer[i+1];
          j++; 
        }
       } else {
        Serial.println("buffer empty"); 
      } 
    }
    
    PacketCount++;     
    RingBuffer[RingEnd].PosTag = PacketCount;
    RingBuffer[RingEnd].PosTag2 = PacketCount;
    RingBuffer[RingEnd].PosTag3 = PacketCount;
    RingBuffer[RingEnd].PosTag4 = 222;
        
    RingEnd = (RingEnd + 1) & (RB_Size-1); 
    noInterrupts();
    if (RingSize > (RB_Size-2)) { 
      Serial.println(" > 30 "); 
      RingBegin = (RingBegin + 1) & (RB_Size-1);  
     }
     else {
      RingSize++;
      PCount++;
    }
    interrupts();
    
    if (sent == true)  {
      sendData(); 
    }     
  }
}

Code: Select all

void sendData() {
  const uint8_t *peer_addr = slave.peer_addr;
  static uint8_t POS;
  
  sent = false; 

  DATA.PosTag = RingBuffer[RingBegin].PosTag;
  DATA.PosTag2 = RingBuffer[RingBegin].PosTag2;
  DATA.PosTag3 = RingBuffer[RingBegin].PosTag3;
  DATA.PosTag4 = RingBuffer[RingBegin].PosTag4;
  esp_err_t result = esp_now_send(peer_addr, DATA.Data, sizeof(DATA.Data));
}

// callback when data is sent from Master to Slave
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  
  if (status != ESP_NOW_SEND_SUCCESS) {  // && (RingSize < 9)) { 
     sendData();
     Serial.println("FAIL");
    }
   else { 
    RingSize--;
    RingBegin = (RingBegin + 1) & (RB_Size-1); 
    PCount--;   
    if (RingSize > 0) {  
      if (RingSize > 12) {
        int BufferDrop = RingSize - 12;
        RingBegin = (RingBegin + BufferDrop) & (RB_Size-1); 
        RingSize -= BufferDrop;
        PCount -= BufferDrop;
        Serial.print("DROP: ");
        Serial.println(BufferDrop);
      }        
      sendData();
     } 
     else 
      sent = true;  
   } 
}
Attachments
Transmitter-i2s-ESPnowTest.zip
(5.84 KiB) Downloaded 218 times

Gregor
Posts: 3
Joined: Fri Apr 30, 2021 2:50 am

Re: 1+1 = 3 ?! Ringbuffer variables go crazy

Postby Gregor » Tue May 04, 2021 1:09 am

Meanwhile, I got some clue where the problem lies. Volatile doesnt make the vars threadsafe, incrementing a variable is not atomic, so if the variable is decremented from another thread during this operation, a count could be lost.

I have to dig deeper into this, any ideas how to solve this problem?

ESP_Sprite
Posts: 9730
Joined: Thu Nov 26, 2015 4:08 am

Re: 1+1 = 3 ?! Ringbuffer variables go crazy

Postby ESP_Sprite » Thu May 06, 2021 4:31 am

The canonical way to fix this is to place (FreeRTOS) mutexes around any code that makes a non-atomic modification to your variables.

Gregor
Posts: 3
Joined: Fri Apr 30, 2021 2:50 am

Re: 1+1 = 3 ?! Ringbuffer variables go crazy

Postby Gregor » Thu May 06, 2021 8:35 pm

Thanks, in the meantime I also found out about this, now it works :-)

Who is online

Users browsing this forum: No registered users and 30 guests