-->
Page 1 of 1

Re: ATOMIC OPERATIONS?

PostPosted: Wed Feb 23, 2022 9:26 am
by durval
Continuing the original discussion here: viewtopic.php?f=9&t=618&start=0
Cc'ing participants: @Necromant @jcmvbkbc @Nurgak @dkinzer
(opened a new topic as it's an old post and I'm not sure what's the forum policy regarding 'necroposting')

Necromant wrote:Is there a proper way to make an atomic section to be 100% sure no interrupt kicks in during it?
is there something like

Code: Select allATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
...
}


we had on avr or spin_lock_irqsave/spin_unlock_irqrestore calls in linux kernel?


Do you really need to disable all interrupts? Similar to spin_lock/unlock operations as in the linux kernel, if all you want is to synchronize access to critical data between code that could end up being run 'simultaneously', why can't you just use a `uint8_t` global variable as a semaphore?

That's what I'm doing here to synchronize access to a ESP-Now message buffer between the ESP-Now receive callbacks and the main loop() code:

Code: Select all
#define ESPNOW_MAXMSGSIZE 250 //maximum message size, from specs

#define ESPNOW_RECV_MSG_STATUS_FREE   0  //Receive buffer message is free (no message received yet, or received and already processed)
#define ESPNOW_RECV_MSG_STATUS_READY  1  //Message in buffer ready to be processed

char    espNowRecvMsgBuf[ESPNOW_MAXMSGSIZE];   //Receive message buffer
uint8_t espNowRecvMsgStatus; //Ditto, access semaphore

[...]

//ESPNow receive callback function
void espNowRecvCB(uint8_t *mac_addr, uint8_t *incomingData, uint8_t len)

  [...]

  while (espNowRecvMsgStatus != ESPNOW_RECV_MSG_STATUS_FREE) {
    //wait for pending receive to be processed so we don't overwrite an unprocessed message in the buffer
    yield();
  }

  //Copy the incoming message into buffer to be processed by program's main execution flow, and set flag
  memcpy(espNowRecvMsgBuf, incomingData, len);
  espNowRecvMsgStatus = ESPNOW_RECV_MSG_STATUS_READY;
}

[...]

loop()
{
  [...]
  //copy the ESP-Now message from the callback receive buffer and reset the semaphore
  if (espNowRecvMsgStatus == ESPNOW_RECV_MSG_STATUS_READY) {
    strcpy(remoteData.espNowLastMsg, espNowRecvMsgBuf);
    espNowRecvMsgStatus = ESPNOW_RECV_MSG_STATUS_FREE;
}
#endif

  [...]
}



Surely loading a single-byte constant into a uint8_t, can't be interrupted?

Or am I misunderstanding something?

Cheers,
-- Durval.

Re: ATOMIC OPERATIONS?

PostPosted: Tue May 24, 2022 9:43 am
by eriksl
I think mandatory exclusive sections are a bad practice and should be avoided as much as possible.

One approach to decimate them is to not actually perform any real code in an interrupt handler. Just flag the interrupt has taken place and clear it. Then, in a sequential background processing scheme the action should be performed. Comparable to Linux "bottom half" functions.