Bir ISR'ın veri yazıp ana döngünün okuduğu, kilitsiz (lock-free) bir circular buffer (ring buffer) yazın.

Cevap

Tek üretici (ISR) ve tek tüketici (main loop) olduğunda, head'i sadece üretici, tail'i sadece tüketici yazarsa kesmeleri kapatmadan güvenli bir ring buffer yazılabilir. Boyutu 2'nin kuvveti seçmek modulo yerine maske kullanmayı sağlar.

#include <stdint.h>
#include <stdbool.h>

#define RB_SIZE 64u                      /* 2'nin kuvveti olmalı */
#define RB_MASK (RB_SIZE - 1u)

typedef struct {
    volatile uint32_t head;              /* sadece üretici yazar */
    volatile uint32_t tail;              /* sadece tüketici yazar */
    uint8_t data[RB_SIZE];
} ringbuf_t;

/* ISR içinden çağrılır (ör. UART RX) */
bool rb_put(ringbuf_t *rb, uint8_t byte)
{
    uint32_t head = rb->head;
    if ((head - rb->tail) == RB_SIZE)    /* dolu */
        return false;
    rb->data[head & RB_MASK] = byte;
    __DMB();                             /* veri, head'den önce görünür olsun */
    rb->head = head + 1u;
    return true;
}

/* Ana döngüden çağrılır */
bool rb_get(ringbuf_t *rb, uint8_t *byte)
{
    uint32_t tail = rb->tail;
    if (rb->head == tail)                /* boş */
        return false;
    *byte = rb->data[tail & RB_MASK];
    __DMB();
    rb->tail = tail + 1u;
    return true;
}

Neden çalışıyor?

  • head ve tail serbestçe artan sayaçlardır; head - tail unsigned aritmetikle sarma (wrap) olsa bile doğru eleman sayısını verir, çünkü RB_SIZE 2^32'yi tam böler.
  • Bu yöntemle buffer'ın tüm RB_SIZE hücresi kullanılır. Klasik "bir hücreyi boş bırak" yöntemine gerek kalmaz.
  • Cortex-M'de hizalı 32-bit okuma/yazma atomiktir. 8-bit bir MCU'da (AVR) 16/32-bit indeks atomik değildir; ya 8-bit indeks kullanın ya da kısa kritik bölge açın.
  • __DMB() (CMSIS) tek çekirdekli Cortex-M0/M3/M4'te çoğu zaman gerekmez ama M7 ve çok çekirdekli sistemlerde yeniden sıralamaya karşı korur. Taşınabilir kod için C11 stdatomic.h ile memory_order_release/acquire kullanılabilir.

Takip soruları

  • Buffer dolunca ne yapılmalı? Yeni veriyi at, en eskinin üzerine yaz veya taşma sayacı tut; hangisi olduğu gereksinime bağlıdır.
  • Birden çok üretici varsa bu tasarım yetmez; kritik bölge veya RTOS queue gerekir.
  1. C dilinde volatile anahtar kelimesi ne işe yarar?OrtaC ProgramlamaEmbedded
  2. Bir yazmaçtaki belirli bir biti set, clear ve toggle eden C kodunu yazın.KolayC ProgramlamaEmbedded
  3. Stack ile heap arasındaki fark nedir? Gömülü sistemlerde dinamik bellek kullanımından neden kaçınılır?OrtaC ProgramlamaEmbedded
  4. Endianness nedir? Little-endian ile big-endian farkı nedir?KolayC ProgramlamaEmbedded
  5. Bit field nedir? Donanım register'larına erişimde bit field mi yoksa bit maskesi mi kullanılmalı?OrtaC ProgramlamaEmbedded
  6. Fonksiyon pointer'ları ve callback tabloları gömülü sistemlerde nasıl kullanılır? Bir state machine örneği verin.OrtaC ProgramlamaEmbedded

Bu konuda başka bir soru biliyor musun?

Mülakatta karşılaştığın soruları ekle, onaylandıktan sonra yayına alınsın.

Soru ekle