Page 1 of 1

1+1 = 3 ?! Ringbuffer variables go crazy

Posted: Sun May 02, 2021 2:28 am
by Gregor
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;  
   } 
}

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

Posted: Tue May 04, 2021 1:09 am
by Gregor
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?

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

Posted: Thu May 06, 2021 4:31 am
by ESP_Sprite
The canonical way to fix this is to place (FreeRTOS) mutexes around any code that makes a non-atomic modification to your variables.

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

Posted: Thu May 06, 2021 8:35 pm
by Gregor
Thanks, in the meantime I also found out about this, now it works :-)