Mengemudi frekuensi output PWM

8

Setelah berjam-jam mencari dan membaca tanpa hasil, saya masih belum memiliki pemahaman lengkap tentang bagaimana dan mengapa menghasilkan frekuensi tertentu dari pin PWM perangkat keras pada RPi tanpa menggunakan 'kotak hitam' orang lain.

Tampaknya ada sedikit informasi yang tidak akurat atau tidak lengkap pada spesifik, serta berbagai istilah yang digunakan - 'pembagi jam', 'siklus tugas', 'rentang PWM' dan data PWM itu sendiri, dan bagaimana mereka semua berhubungan bersama-sama untuk menghasilkan frekuensi tertentu - dalam kasus saya untuk mendorong frekuensi audio tertentu dari sounder piezo.

Neil
sumber

Jawaban:

14

Saya akhirnya mendapatkan pemahaman lengkap (ish) dari file header driver bcm2835.h, jadi saya pikir saya akan memposting dan menjawab pertanyaan saya sendiri untuk orang lain.

Bit yang relevan dari header:

PWM

BCM2835 mendukung PWM perangkat keras pada subset pin GPIO yang terbatas. Pustaka bcm2835 ini menyediakan fungsi untuk mengkonfigurasi dan mengendalikan output PWM pada pin ini.

BCM2835 berisi 2 saluran PWM independen (0 dan 1), yang masing-masing dihubungkan ke subset terbatas pin GPIO. Pin GPIO berikut dapat dihubungkan ke saluran PWM berikut:

  GPIO PIN    RPi pin  PWM Channel    ALT FUN
  12                    0             0
  13                    1             0
  18          1-12      0             5
  19                    1             5
  40                    0             0
  41                    1             0
  45                    1             0
  52                    0             1
  53                    1             1

Agar pin GPIO memancarkan output dari saluran PWM, itu harus diatur ke Fungsi Alt yang diberikan di atas. Perhatikan baik-baik bahwa versi saat ini dari Raspberry Pi hanya memperlihatkan salah satu dari pin ini (GPIO 18 = RPi Pin 1-12) pada header IO, dan oleh karena itu ini adalah satu-satunya pin IO pada RPi yang dapat digunakan untuk PWM. Selanjutnya harus diatur ke ALT FUN 5 untuk mendapatkan output PWM.

Kedua saluran PWM digerakkan oleh clock PWM yang sama, yang clock-dvider-nya dapat divariasikan menggunakan bcm2835_pwm_set_clock(). Setiap saluran dapat diaktifkan secara terpisah bcm2835_pwm_set_mode(). Output rata-rata saluran PWM ditentukan oleh rasio DATA / RANGE untuk saluran itu. Gunakan bcm2835_pwm_set_range()untuk mengatur rentang dan bcm2835_pwm_set_data()untuk mengatur data dalam rasio itu

Setiap saluran PWM dapat berjalan dalam mode Balanced atau Mark-Space. Dalam mode Seimbang, perangkat keras mengirimkan kombinasi pulsa clock yang menghasilkan pulsa DATA keseluruhan per pulsa RANGE. Dalam mode Mark-Space, perangkat keras mengatur output TINGGI untuk lebar pulsa clock DATA, diikuti oleh RENDAH untuk pulsa clock RANGE-DATA.

Jam PWM dapat diatur untuk mengontrol lebar pulsa PWM. Jam PWM berasal dari jam 19.2MHz. Anda dapat mengatur pembagi apa pun, tetapi beberapa pembagi umum disediakan olehbcm2835PWMClockDivider

Misalnya, Anda ingin mengendarai motor DC dengan PWM sekitar 1kHz, dan mengontrol kecepatan kenaikan 1/1024 dari 0/1024 (berhenti) hingga 1024/1024 (penuh). Dalam hal ini Anda dapat mengatur pembagi jam menjadi 16, dan RANGE ke 1024. Frekuensi pengulangan pulsa akan menjadi 1.2MHz / 1024 = 1171.875Hz.

bcm2835PWMClockDividerMenentukan pembagi yang digunakan untuk menghasilkan jam PWM dari jam sistem. Gambar di bawah ini menunjukkan pembagi, periode jam, dan frekuensi jam. Jam dibagi berdasarkan tingkat clock dasar PWM nominal 19,2MHz. Frekuensi yang ditunjukkan untuk setiap pembagi telah dikonfirmasi oleh pengukuran

typedef enum
{
    BCM2835_PWM_CLOCK_DIVIDER_2048  = 2048,    /*!< 2048 = 9.375kHz */
    BCM2835_PWM_CLOCK_DIVIDER_1024  = 1024,    /*!< 1024 = 18.75kHz */
    BCM2835_PWM_CLOCK_DIVIDER_512   = 512,     /*!< 512 = 37.5kHz */
    BCM2835_PWM_CLOCK_DIVIDER_256   = 256,     /*!< 256 = 75kHz */
    BCM2835_PWM_CLOCK_DIVIDER_128   = 128,     /*!< 128 = 150kHz */
    BCM2835_PWM_CLOCK_DIVIDER_64    = 64,      /*!< 64 = 300kHz */
    BCM2835_PWM_CLOCK_DIVIDER_32    = 32,      /*!< 32 = 600.0kHz */
    BCM2835_PWM_CLOCK_DIVIDER_16    = 16,      /*!< 16 = 1.2MHz */
    BCM2835_PWM_CLOCK_DIVIDER_8     = 8,       /*!< 8 = 2.4MHz */
    BCM2835_PWM_CLOCK_DIVIDER_4     = 4,       /*!< 4 = 4.8MHz */
    BCM2835_PWM_CLOCK_DIVIDER_2     = 2,       /*!< 2 = 9.6MHz, fastest you can get */
    BCM2835_PWM_CLOCK_DIVIDER_1     = 1        /*!< 1 = 4.6875kHz, same as divider 4096 */
} bcm2835PWMClockDivider;

Singkatnya:

  1. Jika Anda menginginkan perangkat keras PWM - Anda terjebak dengan pin 12 (BCM18), pin GPIO lainnya akan menggunakan perangkat lunak PWM.

  2. Anda mungkin perlu mengatur mode PWM ke mode 'Mark-Space' untuk kebanyakan kasus penggunaan dan alasan kewarasan seperti dijelaskan di atas.

  3. Dalam mode ini, durasi setiap 'pulsa' adalah TINGGI vs RENDAH ditentukan oleh rasio data PWM dengan rentang PWM - ini terlepas dari kecepatan clock PWM.

  4. Rentang PWM secara efektif adalah 'resolusi' atau jumlah 'divisi' yang mungkin dari setiap pulsa. Semakin banyak pembagian semakin tinggi resolusinya dan dengan demikian semakin banyak negara yang disandikan untuk lebar pulsa yang diberikan.

  5. 'Siklus tugas' adalah rasio data PWM dengan rentang PWM yang dinyatakan sebagai persentase. Rentang PWM 10 dengan data PWM 8 adalah siklus tugas 80%.

  6. Kecepatan clock PWM adalah kekuatan dua pembagi. Jadi kecepatan clock yang Anda pilih untuk PWM harus divisor & (divisor -1) == 0Meskipun nilai-nilai yang valid tercantum di atas.

  7. Membagi frekuensi clock PWM dengan frekuensi output yang diinginkan memberikan nilai rentang pulsa.

  8. Ketika saya sedang encoding audio dan menggunakan sounder piezo saya membutuhkan siklus tugas 50% untuk memaksimalkan osilasi piezo dan volume. Nilai data PWM karenanya selalu setengah dari nilai kisaran PWM - 50% TINGGI 50% RENDAH.

Untuk menghitung frekuensi yang diperlukan, pilih pembagi jam yang masuk akal untuk aplikasi Anda - saya memilih 16, yang setara dengan 1.2Mhz. Begitu:

Nada A adalah 440Hz, F # adalah 370Hz, C # adalah 277Hz

PWMClock = 16; // 1.2Mhz

const A4_RANGE = 1.2e6 / 440;  // 1.2Mhz/440Hz
A4Data = A4_RANGE / 2;

const F4S_RANGE = 1.2e6 / 370;  // 1.2Mhz/370Hz
F4SData = F4S_RANGE / 2;

const C4S_RANGE = 1.2e6 / 277;  // 1.2Mhz/277Hz
C4SData = C4S_RANGE / 2;

Anda dapat dengan mudah menggeser rentang PWM naik dan turun oktaf dalam beberapa - rentang * 2 akan menurunkan satu oktaf, kisaran * 0,5 akan mengambilnya satu.

Jika Anda ingin mengendarai servo di katakan 50Hz perhitungan rentang yang sama berlaku:

PWM Range = PWM frequency / Desired Output Frequency

(Nilai kisaran PWM maksimum menurut beberapa posting secara anekdot adalah 4096 - dalam pengalaman saya ini tidak benar dalam memainkan C # seperti di atas memberikan rentang PWM 4332 yang berfungsi seperti yang diharapkan.)

Seperti kebanyakan hal - mudah ketika Anda tahu caranya.

~ N

Neil
sumber
3
Perhatikan bahwa bit "pin 12 only" berlaku untuk model 26-pin. Model 40 pin memiliki tiga lebih (13, 18, dan 19), tetapi masih ada hanya 2 saluran jam dan pin memiliki hubungan yang tertanam dengan satu atau yang lain (pin 12 dan 18 adalah saluran 0, 13 dan 19 adalah saluran 1); sesuai dengan dokumen yang dikutip di atas libbcm2835 akan memungkinkan Anda untuk mengkonfigurasi kedua saluran dan keempat pin. Fungsi ALT untuk melakukannya berbeda untuk setiap pin; ada tabel di sini yang sebagian besar diangkat langsung dari lembar data Broadcom SoC. Entri yang dicoret hanya pada model 40-pin.
goldilocks
7

Pada Pis baru-baru ini (yang memiliki header ekspansi 40 pin dan modul komputasi) GPIO 12/13/18/19 dapat digunakan untuk menyediakan sinyal PWM perangkat keras.

Sumber clock PWM tidak harus berupa kristal 19.2MHz , pigpio menggunakan 500MHz PLLD.

Untuk metode baris perintah sederhana pengaturan frekuensi PWM perangkat keras, lihat http://abyz.me.uk/rpi/pigpio/pigs.html#HP

joan
sumber