00 PRU nedir?
PRU (Programmable Realtime Unit), Texas Instruments AM335x SoC içinde bulunan bağımsız 32-bit RISC işlemcileridir. Linux tarafından etkilenmeden deterministik, nanosaniye seviyesinde I/O işlemleri yürütürler.
PRU-ICSS Mimarisi
BeagleBone Black'taki AM335x çipi, tek bir PRU-ICSS (Industrial Communication SubSystem) bloğu barındırır. Bu blok iki adet PRU çekirdeği (PRU0 ve PRU1), paylaşımlı bellek, interrupt controller (INTC) ve çeşitli çevre birimlerinden oluşur. Her PRU 32 adet 32-bit genel amaçlı yazmaç içerir ve tek saat döngüsünde bir komut yürütür.
AM335x SoC
├── ARM Cortex-A8 (Linux çalışır)
│ └── remoteproc / rpmsg sürücüleri
└── PRU-ICSS
├── PRU0 (200 MHz, 8 KB inst RAM, 8 KB data RAM)
├── PRU1 (200 MHz, 8 KB inst RAM, 8 KB data RAM)
├── Shared RAM (12 KB)
├── INTC (64 sistem olayı, 10 host IRQ)
├── IEP (Industrial Ethernet Peripheral — zamanlayıcı)
└── MII_RT (Ethernet MII arayüzü)
200 MHz Sabit Gecikme
PRU, 200 MHz'de çalışır; yani her komut tam olarak 5 ns sürer. Bellek erişimi, I/O toggle ve döngü sayımları tamamen deterministiktir. Linux tarafındaki kesme gecikmesi, zamanlayıcı jiteri veya önbellek ısınması PRU yürütmesini etkilemez. Bu özellik, PRU'yu şu senaryolar için ideal kılar:
ARM ile karşılaştırma
| Özellik | ARM Cortex-A8 (Linux) | PRU |
|---|---|---|
| Frekans | 1 GHz | 200 MHz |
| Zamanlama deterministikliği | Yok (OS jitter) | Tam (tek döngü kesin) |
| Minimum GPIO toggle | ~1 µs (tipik) | 5 ns |
| Bellek koruması | MMU + sanal adres | Fiziksel adres, MMU yok |
| İşletim sistemi | Linux | Bare-metal firmware |
01 Donanım kaynakları
PRU-ICSS bloğunun barındırdığı donanım kaynakları, firmware tasarımını doğrudan etkiler. Her birimin kapasitesini ve sınırlamalarını iyi anlamak gerekir.
PRU0 ve PRU1 Çekirdekleri
Her PRU çekirdeği kendi bellek alanına sahiptir ve birbirinden bağımsız çalışabilir. Ancak paylaşımlı RAM ve INTC aracılığıyla birbirleriyle ve ARM ile haberleşirler.
IEP Zamanlayıcısı
IEP (Industrial Ethernet Peripheral), 32-bit donanım zamanlayıcısı olarak kullanılabilir. PRU firmware'i IEP ile periyodik görevler zamanlayabilir veya olaylar arasındaki süreyi nanosaniye çözünürlüğüyle ölçebilir.
/* IEP zamanlayıcısını başlatmak */
CT_IEP.TMR_GLB_CFG_bit.CNT_EN = 1; /* sayacı etkinleştir */
CT_IEP.TMR_GLB_CFG_bit.DEFAULT_INC = 1; /* her döngüde 1 artır */
/* Mevcut zamanı oku */
uint32_t t_start = CT_IEP.TMR_CNT;
/* ... işlem ... */
uint32_t elapsed_ns = (CT_IEP.TMR_CNT - t_start) * 5; /* 5 ns/döngü */
eCAP (Enhanced Capture)
PRU-ICSS içindeki eCAP modülü, gelen sinyal kenarlarını (yükselen/düşen) donanım düzeyinde zaman damgalamak için kullanılır. Yazılım döngüsü gerekmeksizin PWM frekans/duty ölçümü yapılabilir.
UART
PRU-ICSS, 115200 baud'a kadar çalışabilen bir donanım UART birimini barındırır. PRU firmware'i bu UART'ı Linux seri konsolu veya özel protokol arayüzü olarak kullanabilir.
Fiziksel Pin Eşlemeleri
| PRU Birimi | BeagleBone Header | AM335x Sinyal Adı | Notlar |
|---|---|---|---|
| PRU0 GPO[0] | P9.31 | pr1_pru0_pru_r30[0] | Çıkış |
| PRU0 GPI[0] | P9.31 | pr1_pru0_pru_r31[0] | Giriş (aynı pin, farklı mod) |
| PRU1 GPO[0] | P8.45 | pr1_pru1_pru_r30[0] | Çıkış |
| PRU1 GPO[1] | P8.46 | pr1_pru1_pru_r30[1] | Çıkış |
| PRU0 UART TX | P9.17 | pr1_uart0_txd | UART0 TX |
02 Geliştirme ortamı kurulumu
PRU firmware'i derlemek için TI'ın resmi PRU Code Generation Tools (PRU-CGT) ve destekleyici yazılım paketi (pru-software-support-package) gereklidir.
Gerekli bileşenler
Ubuntu/Debian üzerinde kurulum
# TI resmi PPA üzerinden PRU araçları
sudo add-apt-repository ppa:beagleboard/ppa
sudo apt-get update
sudo apt-get install ti-pru-cgt-installer
# pru-software-support paketi (başlık dosyaları)
git clone https://git.ti.com/pru-software-support-package/pru-software-support-package.git
export PRU_SSP=$(pwd)/pru-software-support-package
# Derleyici yolunu ayarla
export PRU_CGT=/usr/share/ti/cgt-pru
export PATH=$PRU_CGT/bin:$PATH
# Kurulumu doğrula
clpru --version
BeagleBone üzerinde yerinde kurulum
Debian Buster veya Bullseye çalıştıran BeagleBone'da PRU araçları paket deposundan yüklenebilir:
# BeagleBone Debian deposu üzerinden
sudo apt-get update
sudo apt-get install pru-software-support am335x-pru-package
# Kernel PRU sürücülerini kontrol et
lsmod | grep pru
# pru_rproc ve rpmsg_pru yüklü olmalı
# PRU remoteproc sysfs düğümleri
ls /sys/bus/platform/drivers/pru-rproc/
Dizin yapısı
pru-projesi/
├── Makefile
├── resource_table.h # remoteproc kaynak tablosu
├── main.c # PRU C kaynak kodu
├── AM335x_PRU.cmd # Linker command dosyası
└── gen/
├── main.out # ELF çıktısı
└── main.map # Bellek haritası
Temel Makefile
PRU_CGT ?= /usr/share/ti/cgt-pru
PRU_SSP ?= /usr/lib/ti/pru-software-support-package
CC = clpru
CFLAGS = --include_path=$(PRU_SSP)/include \
--include_path=$(PRU_SSP)/include/am335x \
-v3 -O2 --display_error_number \
--endian=little --hardware_mac=yes
LFLAGS = --reread_libs --warn_sections \
--stack_size=0x100 --heap_size=0x100
TARGET = gen/main.out
SOURCES = main.c
all: $(TARGET)
$(TARGET): $(SOURCES)
mkdir -p gen
$(CC) $(CFLAGS) -z -i$(PRU_CGT)/lib -i$(PRU_CGT)/include \
$(LFLAGS) -o $@ $(SOURCES) AM335x_PRU.cmd
clean:
rm -rf gen/
03 PRU firmware yazımı
PRU firmware, C dili ile yazılır; ancak standart libc mevcut değildir ve çevre birimine doğrudan yazmaç erişimi gereklidir. Resource table yapısı, remoteproc ile iletişim kurmak için zorunludur.
Resource Table
Her PRU firmware, resource_table bölümünde bir kaynak tablosu tanımlamalıdır. Bu tablo remoteproc çerçevesine hangi RPMsg kanallarının, vring'lerin ve memory mapping'lerinin gerektiğini bildirir.
#ifndef _RSC_TABLE_PRU_H_
#define _RSC_TABLE_PRU_H_
#include <stddef.h>
#include <rsc_types.h>
#define NUM_VDEVS 1
#define NUM_RPMSG_CHNLS 1
struct my_resource_table {
struct resource_table base;
uint32_t offset[1];
struct fw_rsc_vdev rpmsg_vdev;
struct fw_rsc_vdev_vring rpmsg_vring0;
struct fw_rsc_vdev_vring rpmsg_vring1;
};
#pragma DATA_SECTION(pru_remoteproc_ResourceTable, ".resource_table")
#pragma RETAIN(pru_remoteproc_ResourceTable)
struct my_resource_table pru_remoteproc_ResourceTable = {
{ 1, NUM_VDEVS, 0, 0, },
{ offsetof(struct my_resource_table, rpmsg_vdev), },
{ TYPE_VDEV, VIRTIO_ID_RPMSG, 0,
RPMSG_PRU_C0_FEATURES, 0, 0, 0, NUM_RPMSG_CHNLS, { 0, 0 },
},
{ PRU_D_STACK_SIZE, 16, 4, 1, 0 },
{ PRU_D_STACK_SIZE + 0x2000, 16, 4, 2, 0 },
};
Temel PRU C programı
#include <stdint.h>
#include <pru_cfg.h>
#include <pru_intc.h>
#include "resource_table.h"
volatile register uint32_t __R30; /* GPO çıkış yazmaç */
volatile register uint32_t __R31; /* GPI giriş yazmaç */
#define SHARED_MEM_ADDR 0x00010000
volatile uint32_t *shared_mem = (volatile uint32_t *)SHARED_MEM_ADDR;
static inline void delay_ns(uint32_t ns) {
uint32_t cycles = ns / 5;
while (cycles--) {
__delay_cycles(1);
}
}
void main(void) {
/* OCP master bağlantısını etkinleştir */
CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;
while (1) {
uint32_t cmd = shared_mem[0];
if (cmd == 1) {
__R30 |= (1u << 0); /* GPO0 yüksek */
delay_ns(500);
__R30 &= ~(1u << 0); /* GPO0 düşük */
shared_mem[0] = 0; /* komutu temizle */
}
__delay_cycles(10);
}
}
INTC yapılandırması
PRU, ARM'dan sinyal almak için INTC üzerinden kesme alabilir. Sistem olayları (system events) PRU kanallarına eşlenerek "mailbox" benzeri bir mekanizma oluşturulur.
/* INTC başlatma — PRU0 system event 16 bekle */
CT_INTC.SICR_bit.STS_CLR_IDX = 16; /* event 16'yı temizle */
CT_INTC.EISR_bit.EN_SET_IDX = 16; /* event 16'yı etkinleştir */
/* Kesme bekle (host interrupt 0 = R31 bit 30) */
while ((__R31 & (1u << 30)) == 0) {
/* bekleniyor */
}
CT_INTC.SICR_bit.STS_CLR_IDX = 16; /* event'i temizle */
04 remoteproc ile yükleme
Linux, PRU firmware'ini remoteproc çerçevesi üzerinden yükler ve yönetir. Firmware ELF dosyası /lib/firmware/ dizinine kopyalanır; ardından sysfs üzerinden PRU başlatılıp durdurulabilir.
remoteproc sürücü mimarisi
Linux Kullanıcı Alanı
|
| sysfs: /sys/class/remoteproc/remoteproc1/state
v
pru_rproc.ko (kernel sürücüsü)
|-- Firmware yükle: /lib/firmware/am335x-pru0-fw
|-- ELF ayrıştır: resource_table oku
|-- Bellek eşle: IRAM / DRAM / Shared RAM
|-- INTC yapılandır
v
PRU0 Çekirdeği (firmware çalışıyor)
Firmware dağıtımı
# Derlenmiş firmware'i yerleştir
sudo cp gen/main.out /lib/firmware/am335x-pru0-fw
# Sembolik bağlantıyı kontrol et
ls -la /lib/firmware/ | grep pru
sysfs üzerinden PRU kontrolü
# remoteproc düğümlerini listele
ls /sys/class/remoteproc/
# remoteproc0 remoteproc1 (PRU0 ve PRU1)
# PRU0 için firmware adını ayarla
echo "am335x-pru0-fw" | sudo tee /sys/class/remoteproc/remoteproc1/firmware
# PRU0'ı başlat
echo "start" | sudo tee /sys/class/remoteproc/remoteproc1/state
# Durumu kontrol et
cat /sys/class/remoteproc/remoteproc1/state
# "running" çıktısı beklenir
# PRU0'ı durdur
echo "stop" | sudo tee /sys/class/remoteproc/remoteproc1/state
Kernel mesajlarını izleme
# PRU yükleme/başlatma günlüklerini takip et
dmesg -w | grep -i pru
# Beklenen çıktı:
# remoteproc remoteproc1: powering up 4a334000.pru
# remoteproc remoteproc1: Booting fw image am335x-pru0-fw, size 49152
# remoteproc remoteproc1: remote processor 4a334000.pru is now up
# rpmsg_pru virtio0.rpmsg-pru.-1.30: new rpmsg_pru channel: 30
remoteproc durum makinesi
Device Tree düğümü
/* arch/arm/boot/dts/am33xx-l4.dtsi içindeki PRU düğümü */
pru0: pru@4a334000 {
compatible = "ti,am3356-pru";
reg = <0x4a334000 0x2000>, /* IRAM */
<0x4a322000 0x400>, /* control */
<0x4a322400 0x100>; /* debug */
firmware-name = "am335x-pru0-fw";
};
05 RPMsg ile haberleşme
RPMsg (Remote Processor Messaging), PRU ve ARM çekirdeği arasında çift yönlü, mesaj tabanlı iletişim sağlar. Linux tarafında /dev/rpmsg_pruN karakter aygıtı üzerinden erişilir.
RPMsg mimarisi
Linux Kullanıcı Alanı
| open("/dev/rpmsg_pru30")
| write(fd, msg, len) / read(fd, buf, sizeof(buf))
v
rpmsg_pru.ko (kernel sürücüsü)
|
| virtqueue (vring üzerinden)
v
PRU Firmware
| pru_rpmsg_receive()
| pru_rpmsg_send()
v
(işlem + yanıt)
PRU firmware — RPMsg başlatma
#include <pru_rpmsg.h>
#include <pru_virtqueue.h>
struct pru_rpmsg_transport transport;
uint16_t src, dst, len;
char payload[RPMSG_BUF_SIZE];
void main(void) {
volatile uint8_t *status;
CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;
/* VDEV'in hazır olmasını bekle */
status = &resourceTable.rpmsg_vdev.status;
while (!(*status & VIRTIO_CONFIG_S_DRIVER_OK));
/* Transport başlat */
pru_rpmsg_init(&transport,
&resourceTable.rpmsg_vring0,
&resourceTable.rpmsg_vring1,
TO_ARM_HOST, FROM_ARM_HOST);
/* RPMsg kanalını duyur */
while (pru_rpmsg_channel(RPMSG_NS_CREATE, &transport,
CHAN_NAME, CHAN_DESC, CHAN_PORT) != PRU_RPMSG_SUCCESS);
/* Ping-pong döngüsü */
while (1) {
if (__R31 & HOST_INT) {
CT_INTC.SICR_bit.STS_CLR_IDX = FROM_ARM_HOST;
while (pru_rpmsg_receive(&transport, &src, &dst,
payload, &len) == PRU_RPMSG_SUCCESS) {
/* Echo: aynı mesajı geri gönder */
pru_rpmsg_send(&transport, dst, src, payload, len);
}
}
}
}
Linux kullanıcı alanı
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(void) {
int fd;
char tx_buf[] = "merhaba PRU";
char rx_buf[512];
ssize_t n;
fd = open("/dev/rpmsg_pru30", O_RDWR);
if (fd < 0) { perror("open"); return 1; }
write(fd, tx_buf, strlen(tx_buf));
n = read(fd, rx_buf, sizeof(rx_buf));
if (n > 0) {
rx_buf[n] = '\0';
printf("PRU yaniti: %s\n", rx_buf);
}
close(fd);
return 0;
}
RPMsg kanal referansları
06 GPIO ve pin multiplexing
BeagleBone Black'taki her pin birden fazla işlev için kullanılabilir. PRU girişi/çıkışı olarak kullanmak için Device Tree overlay ile pin mux ayarlanmalıdır.
Pin Mux Kavramı
AM335x'in her I/O pini, pinmux register üzerinden 8 farklı "mod" seçeneğinden birine ayarlanabilir. PRU için pruout veya pruin modu seçilmelidir. Mod numaraları pin başına farklıdır; AM335x Technical Reference Manual'dan doğrulanmalıdır.
| Mod Biti | Anlamı |
|---|---|
| MUX_MODE (2:0) | 0–7 arası fonksiyon seçimi (pruout genellikle 5 veya 6) |
| PULL_UP (4) | Dahili pull-up direnci etkinleştir |
| PULL_DOWN (3) | Dahili pull-down direnci etkinleştir (varsayılan) |
| RXACTIVE (5) | Giriş tamponu etkinleştir — GPI için zorunlu |
| SLEWCTRL (6) | 0 = hızlı, 1 = yavaş kenar |
Device Tree overlay
/dts-v1/;
/plugin/;
/ {
compatible = "ti,beaglebone-black";
part-number = "BBB-PRU0-GPIO";
version = "00A0";
fragment@0 {
target = <&am33xx_pinmux>;
__overlay__ {
pru0_gpio_pins: pru0_gpio_pins {
pinctrl-single,pins = <
/* P9.31 = offset 0x190, mode 5 = GPO (pruout) */
0x190 0x05
/* P9.29 = offset 0x194, mode 5 = GPO */
0x194 0x05
/* P9.28 = offset 0x19C, mode 6 + RXACTIVE = GPI */
0x19C 0x26
>;
};
};
};
};
Overlay derleme ve yükleme
# DTS'i DTB overlay formatına derle
dtc -O dtb -o am335x-boneblack-pru0-gpio-00A0.dtbo \
-b 0 -@ am335x-boneblack-pru0-gpio.dts
sudo cp am335x-boneblack-pru0-gpio-00A0.dtbo /lib/firmware/
# Yeni kernel (4.19+) ile config-pin kullanımı
config-pin P9.31 pruout
config-pin P9.29 pruout
config-pin P9.28 pruin
# Mevcut modu doğrula
config-pin -q P9.31
Firmware içinde GPO/GPI kullanımı
volatile register uint32_t __R30; /* GPO */
volatile register uint32_t __R31; /* GPI */
/* P9.31 pini yüksek yap (PRU0 GPO bit 0) */
__R30 |= (1u << 0);
/* P9.29 pini yüksek yap (PRU0 GPO bit 1) */
__R30 |= (1u << 1);
/* Tüm GPO'yu atomik olarak ayarla */
__R30 = 0x00000003;
/* P9.28 pini oku (PRU0 GPI bit 3) */
uint8_t pin_val = (__R31 >> 3) & 1;
07 Gerçek senaryo: WS2812 LED sürücüsü
WS2812 (NeoPixel) RGB LED'ler, 800 kHz taşıyıcı ve kesin darbe genişliği gerektiren tek-kablo protokol kullanır. PRU'nun deterministik zamanlaması bu protokol için biçilmiş kaftandır.
WS2812 Protokolü
Her LED 24-bit GRB veri (8-bit G, 8-bit R, 8-bit B) alır. Her bit, yüksek ve düşük darbe süresiyle kodlanır:
PRU Zamanlaması (200 MHz = 5 ns/döngü):
Bit-1: [HIGH: 160 döngü][LOW: 90 döngü] toplam = 1250 ns
Bit-0: [HIGH: 80 döngü][LOW: 170 döngü] toplam = 1250 ns
Reset: [LOW: 10000 döngü] = 50 µs
WS2812 PRU firmware
#include <stdint.h>
#include <pru_cfg.h>
#include "resource_table.h"
volatile register uint32_t __R30;
#define DATA_PIN_BIT 0u
#define SHARED_MEM 0x00010000u
#define MAX_LEDS 60u
typedef struct { uint8_t g, r, b; } rgb_t;
volatile rgb_t *led_buf = (volatile rgb_t *)SHARED_MEM;
volatile uint32_t *cmd = (volatile uint32_t *)(SHARED_MEM + MAX_LEDS * 3 + 4);
static void send_bit(uint8_t bit) {
if (bit) {
__R30 |= (1u << DATA_PIN_BIT);
__delay_cycles(158);
__R30 &= ~(1u << DATA_PIN_BIT);
__delay_cycles(88);
} else {
__R30 |= (1u << DATA_PIN_BIT);
__delay_cycles(78);
__R30 &= ~(1u << DATA_PIN_BIT);
__delay_cycles(168);
}
}
static void send_byte(uint8_t byte) {
int i;
for (i = 7; i >= 0; i--) {
send_bit((byte >> i) & 1);
}
}
static void send_reset(void) {
__R30 &= ~(1u << DATA_PIN_BIT);
__delay_cycles(10000);
}
void main(void) {
uint32_t i, n_leds;
CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;
while (1) {
if (*cmd > 0) {
n_leds = (*cmd > MAX_LEDS) ? MAX_LEDS : *cmd;
for (i = 0; i < n_leds; i++) {
send_byte(led_buf[i].g);
send_byte(led_buf[i].r);
send_byte(led_buf[i].b);
}
send_reset();
*cmd = 0; /* tamamlandı */
}
}
}
Linux kullanıcı alanı kontrolü
#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#define PRUSS_SHAREDMEM_BASE 0x4A310000
#define PRUSS_MAP_SIZE 0x40000
#define MAX_LEDS 60
typedef struct { uint8_t g, r, b; } rgb_t;
int main(void) {
int mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
void *base = mmap(NULL, PRUSS_MAP_SIZE,
PROT_READ | PROT_WRITE,
MAP_SHARED, mem_fd,
PRUSS_SHAREDMEM_BASE);
rgb_t *leds = (rgb_t *)base;
volatile uint32_t *cmd = (volatile uint32_t *)(base + MAX_LEDS * 3 + 4);
/* Gökkuşağı efekti */
int i;
for (i = 0; i < MAX_LEDS; i++) {
leds[i].r = (i * 4) & 0xFF;
leds[i].g = ((i + 20) * 4) & 0xFF;
leds[i].b = ((i + 40) * 4) & 0xFF;
}
*cmd = MAX_LEDS;
while (*cmd != 0); /* tamamlanmayı bekle */
munmap(base, PRUSS_MAP_SIZE);
close(mem_fd);
return 0;
}
08 Hata ayıklama
PRU firmware hata ayıklaması, klasik GDB akışından farklıdır. Paylaşımlı bellek dökümü, IEP zamanlayıcısı tabanlı profilleme ve remoteproc crash kurtarma temel tekniklerdir.
Shared Memory Log ile hata tespiti
/* PRU firmware — debug mesajı shared mem'e yaz */
#define DBG_MEM 0x00010F00u
volatile uint32_t *dbg = (volatile uint32_t *)DBG_MEM;
void pru_assert(uint32_t cond, uint32_t code) {
if (!cond) {
dbg[0] = 0xDEADBEEFu;
dbg[1] = code;
dbg[2] = CT_IEP.TMR_CNT; /* nanosaniye zaman damgası */
while (1); /* PRU'yu durdur */
}
}
/* Linux — shared mem okuma */
int fd = open("/dev/mem", O_RDONLY);
uint32_t *base = mmap(NULL, 0x40000, PROT_READ,
MAP_SHARED, fd, 0x4A310000);
volatile uint32_t *dbg = base + (0x0F00 / 4);
if (dbg[0] == 0xDEADBEEF) {
printf("PRU HATA: kod=0x%08X, t=%u döngü\n", dbg[1], dbg[2]);
}
remoteproc crash kurtarma
# PRU durumunu kontrol et
cat /sys/class/remoteproc/remoteproc1/state
# "crashed" ise yeniden başlat:
echo "stop" | sudo tee /sys/class/remoteproc/remoteproc1/state
dmesg | tail -30 | grep -i "pru\|remoteproc"
sudo cp gen/main_fixed.out /lib/firmware/am335x-pru0-fw
echo "start" | sudo tee /sys/class/remoteproc/remoteproc1/state
Logic analyzer ile doğrulama
WS2812 gibi kesin zamanlama protokollerinde yazılım analizörü yeterli değildir. Sigrok / PulseView ile ucuz bir logic analyzer (örn. DSLogic) kullanarak PRU çıkış pinini örneklemek, gerçek darbe genişliklerini doğrulamak için en güvenilir yöntemdir.
IEP ile performans profilleme
CT_IEP.TMR_GLB_CFG_bit.CNT_EN = 1;
uint32_t t0 = CT_IEP.TMR_CNT;
/* ... ölçülecek kod ... */
uint32_t t1 = CT_IEP.TMR_CNT;
/* Sonucu shared mem'e yaz */
shared_mem[10] = (t1 - t0) * 5; /* nanosaniye cinsinden */
Sık karşılaşılan sorunlar
| Sorun | Olası Neden | Çözüm |
|---|---|---|
| PRU "crashed" durumuna geçiyor | IRAM taşması, yanlış bellek erişimi | Linker map dosyasını kontrol et, adres sınırlarını doğrula |
| /dev/rpmsg_pru30 oluşmuyor | Resource table yanlış, VDEV hazır değil | resource_table.h'yi doğrula, dmesg'i incele |
| GPIO çıkışı yok | Pin mux ayarı eksik veya yanlış | config-pin ile pin modunu doğrula |
| WS2812 renk hatalı | Gecikme döngüsü sayısı yanlış | Logic analyzer ile darbe süresini ölç, kalibre et |
| Firmware yüklenmiyor | /lib/firmware/ dosyası eksik veya bozuk | file gen/main.out ile ELF formatını kontrol et |