Güzel blog yazısı, FPGA ve STM32 arasındaki SPI iletişimini ayrıntılı olarak analiz eder (2)

Bir omuz sırt çantası

Bu ne kadar zor?

Bir şans ver!

_

Uzun basın tanıma

[Konu]: FPGA ve STM32 arasındaki SPI iletişiminin ayrıntılı analizi (2)

[Yazar]: LinCoding

[Beyan]: Yeniden yazdırın, alıntı yapın, lütfen kaynağı belirtin

Bu makale devam ediyor - FPGA ve STM32 arasındaki SPI iletişiminin ayrıntılı bir analizi (1) Gerçekten çok fazla içerik var ve bunu iki makaleye bölmem gerekiyor. Yukarıda bahsedildiği gibi FPGA, STM32 tarafından gönderilen SPI protokolünü taklit etmek için kullanılır.

1. SPI_Receiver modülünün programı:

modül spi_receiver (inputclk, // global saat inputrst_n, // global sıfırlama inputspi_cs, inputspi_sck, inputspi_mosi, outputreg rxd_data, outputregrxd_flag);

İlk bölüm girdi ve çıktının tanımıdır, söylenecek bir şey yok, Veri alan modüller için, diğer modüllerin verileri okuyabilmesi için bir alma tamamlama bayrağı sinyali ekleyin .

// ----------------------------------- // giriş sinyalini senkronize edin regspi_cs_r0, spi_cs_r1; regspi_sck_r0, spi_sck_r1 ; regspi_mosi_r0, spi_mosi_r1; her zaman @ (posedge clk veya negedge rst_n) başlarsa (! rst_n) spi_cs_r0 başlasa < = 1'b1; spi_cs_r1 < = 1'b1; spi_sck_r0 < = 1'b0; spi_sck_r1 < = 1'b0; spi_mosi_r0 < = 1'b0; spi_mosi_r1 < = 1'b0; başka son spi_cs_r0 başlar < = spi_cs; spi_cs_r1 < = spi_cs_r0; spi_sck_r0 < = spi_sck; spi_sck_r1 < = spi_sck_r0; spi_mosi_r0 < = spi_mosi; spi_mosi_r1 < = spi_mosi_r0; end end regrxd_cnt / * synthesis noprune * /; wiremcu_cs = spi_cs_r1; wiremcu_data = spi_mosi_r1; wiremcu_read_flag = (spi_sck_r0 ve ~ spi_sck_r0 ve ~ spi_sck_r0 ve ~ spi_sck_r0 ve ~ spi_sck_r0 ve ~ spi_sck_r0) ve (rxd_cnt == 4'd8))? 1'b1: 1'b0;

İkinci bölüm önemli bir noktadır:

Öncelikle FPGA bir slave gibi davrandığından ve STM32 tarafından gönderilen CS, SCK ve MOSI sinyallerini aldığından, bu tür asenkron sinyaller için ana saatin senkronizasyon işlemi için kullanılması gerekir En yaygın yöntem iki vuruş yapmaktır. Yazıda bahsediliyor.

İkinci olarak, STM32'nin SPI modu SPI_CPOL_Low ve SPI_CPHA_1Edge olarak seçildiğinden, örnekleme SCK saatinin yükselen kenarında yapılır, böylece SCK'nın yükselen kenarını yakalamak için mcu_read_flag sinyali tanımlanır.

Son olarak, 8 bitlik verinin ne zaman okunduğunu bilmemiz gerekiyor.Önceki makaledeki osiloskoptaki şekle göre, CS'nin yükselen kenarı veri okuma tamamlama bayrağı olarak kullanılabilir, bu nedenle mcu_read_done sinyali CS'nin yükselişini izlemek için tanımlanır. Bununla birlikte, STM32, sıfırlama aşamasında CS titreşmesine sahip olacağından, verileri doğru hale getirmek için rxd_cnt == 8 koşulunu eklemek en iyisidir!

// ----------------------------------- // örnek girdi MOSI regrxd_data_r; her zaman @ (posedge clk veya negedge rst_n) başla eğer (! rst_n) rxd_cnt < = 4'd0; rxd_data_r < = 8'd0; eğer (! Mcu_cs) eğer (mcu_read_flag) rxd_data_r başlarsa < = mcu_data; rxd_cnt < = rxd_cnt + 1'b1; başka son, rxd_data_r başlar < = rxd_data_r; rxd_cnt < = rxd_cnt; başka sonla başlar rxd_data_r < = rxd_data_r; rxd_cnt < = 4'd0; bitiş sonu

Üçüncü kısım veriyi örneklemektir.Resime bakın ve konuşun Yazar, testbench'de 0xaa, 0x55 ve 0xff olmak üzere üç sayı gönderdi.Tümünün mükemmel bir şekilde tespit edilebildiğini görebilirsiniz.

Burada dikkat edilmesi gereken bir sorun var:

Yukarıdaki kodun bir bölümü aşağıdaki koda yeniden yazılabilir mi?

else if (mcu_read_flag! mcu_cs) rxd_data_r başlar < = mcu_data; rxd_cnt < = rxd_cnt + 1'b1; başka son, rxd_data_r başlar < = rxd_data_r; rxd_cnt < = rxd_cnt; son

Bu, kodu çok kısa yapıyor gibi görünüyor, ancak rxd_cnt yazmak için yer yok < = 4'd0; rxd_cnt'nin başlangıç değerini geri yükleyememesini sağlar. Bu nedenle yazar aşağıdaki şekilde değişiklik yapmıştır:

else if (mcu_read_flag! mcu_cs) if (rxd_cnt < 4'd8) rxd_data_r başlar < = mcu_data; rxd_cnt < = rxd_cnt + 1'b1; başka son, rxd_data_r başlar < = rxd_data_r; rxd_cnt < = 4'd0; başka bir son rxd_data_r başlar < = rxd_data_r; rxd_cnt < = rxd_cnt; son

İdeal çok güzel, tamam olduğunu hissediyorum, simülasyona bakalım:

Sonuç olarak, rxd_cnt'yi temizlemek için mcu_read_flag olmadığından yalnızca ilk 0xaa tanınabilir! Bu nedenle, onu orijinal haliyle yazmaktan başka yolu yoktur!

// ----------------------------------- // her zaman @ çıktı (posedge clk veya negedge rst_n) eğer (! rst_n) rxd_data başlasın < = 8'd0; rxd_flag < = 1'b0; eğer (mcu_read_done) rxd_data başlarsa < = rxd_data_r; rxd_flag < = 1'b1; aksi takdirde end rxd_data başlar < = rxd_data; rxd_flag < = 1'b0; bitiş sonu

Dördüncü bölüm, anahtar geri alma deneyinde kullanılan rxd_data ve rxd_flag'ın eşzamanlı çıkışıdır, aşağıdaki simülasyon diyagramına bakınız:

============================================= = ===

2. Aşağıdaki SPI_Transfer modülünün programıdır:

modül spi_transfer (inputclk, // global saat inputrst_n, // global sıfırlama inputspi_cs, inputspi_sck, outputregspi_miso, inputtxd_en, girdi txd_data, outputregtxd_flag);

İlk bölüm girdi ve çıktının tanımı, açıklanması gerekenler Modül göndermek için, ister seri port iletimi ister SPI iletimi olsun, bir etkinleştirme sinyali göndermek gerekir , Bu örnekte txd_en gibi.

Tabii ki, gönderme etkinleştirildiğinde, ne düşünüyorsunuz?

Etkinleştirme sinyalinin gelişini beklemek için durum makinesinin IDLE'sini kullanmaktır! Yazar bu makalede- "74HC595 Sürücüsünün Ayrıntılı Analizi" dedi! Bu nedenle, ilgili rutinlere ve kalıplara hakim olduğunuz sürece Verilog programları yazmak hiç de zor değil! Tabii ki, alıcı modülün rxd_flag'ı gibi, iletim tamamlama bayrak sinyali txd_flag de diğer modüllerin kullanması için vazgeçilmezdir.

// ----------------------------------- // giriş sinyalini senkronize edin regspi_cs_r0, spi_cs_r1; regspi_sck_r0, spi_sck_r1 ; her zaman @ (posedge clk veya negedge rst_n) başlasa (! rst_n) spi_cs_r0 < = 1'b1; spi_cs_r1 < = 1'b1; spi_sck_r0 < = 1'b0; spi_sck_r1 < = 1'b0; başka son spi_cs_r0 başlar < = spi_cs; spi_cs_r1 < = spi_cs_r0; spi_sck_r0 < = spi_sck; spi_sck_r1 < = spi_sck_r0; end end wiremcu_cs = spi_cs_r1; wiremcu_write_flag = (~ spi_sck_r0 ve spi_sck_r1)? 1'b1: 1'b0; // sck negedge yakalama wiremcu_write_done = (spi_cs_r0 ve ~; cs poz yakalama wiremcu_write_start = (~ spi_cs_r0 ve spi_cs_r1)? 1'b1: 1'b0; // cs negedge yakalama

İkinci kısım spi_receiver kısmına benzer, bu yüzden daha fazlasını tanıtmayacağım!

// ----------------------------------- // FSM: localparamT_IDLE kodla = 2'd0; localparamT_START = 2'd1; localparamT_SEND = 2'd2; localparamSPI_MISO_DEFAULT = 1'b1; // -------------------------------- --- // FSM regtxd_state'i aktar; regtxd_cnt / * synthesis noprune * /; her zaman @ (posedge clk veya negedge rst_n), (! rst_n) başlarsa başlar txd_cnt < = 4'd0; spi_miso < = SPI_MISO_DEFAULT; txd_state < = T_IDLE; başka durumu sonlandır (txd_state) T_IDLE: txd_cnt'ye başla < = 4'd0; spi_miso < = SPI_MISO_DEFAULT; if (txd_en) txd_state < = T_START; başka txd_state < = T_IDLE; end T_START: (mcu_write_start) spi_miso başlarsa başla < = txd_data; txd_cnt < = txd_cnt + 1'b1; txd_state < = T_SEND; başka sonda spi_miso başlar < = spi_miso; txd_cnt < = txd_cnt; txd_state < = T_START; bitiş T_SEND: başla (mcu_write_done) txd_state < = T_IDLE; başka txd_state < = T_SEND; eğer (! Mcu_cs) if (mcu_write_flag) başlarsa (txd_cnt < 4'd8) spi_miso'yu başlat < = txd_data; txd_cnt < = txd_cnt + 1'b1; başka sonda spi_miso başlar < = 1'b1; txd_cnt < = txd_cnt; end end else begin spi_miso < = spi_miso; txd_cnt < = txd_cnt; end else end spi_miso başlar < = SPI_MISO_DEFAULT; txd_cnt < = 4'd0; bitiş varsayılanı: txd_cnt ile başlar < = 4'd0; spi_miso < = SPI_MISO_DEFAULT; txd_state < = T_IDLE; son harf sonu

Üçüncü kısım, uzun iletim durumu makinesidir.İlk olarak, etkinleştirme sinyalinin BOŞTA durumda gelişini bekleyin ve etkinleştirme sinyalinin gelmesinden sonra iletim durumuna girin.

Unutulmaması gereken bir nokta, ilk veri gönderildiğinde yazarın gönderme durumu CS sinyalinin düşen kenarını bir işaret olarak alın Ve sonraki tüm veri aktarımları SCK'nın düşen kenarını bir işaret olarak alın , Bu neden? Lütfen simülasyon şemasına bakın:

FPGA, STM32'ye veri gönderdiğinde, STM32'nin SCK'nın yükselen kenarında okuyacağı görülebilir.FpGA, veriyi sadece SCK'nın ilk yükselen kenarı olan SCK'nın düşen kenarı üzerine ayarlarsa, çünkü FPGA henüz veri ayarlamamıştır. STM32'nin yüksek seviyeyi almasına neden olur, yani hangi veri gönderilirse gönderilsin, 8 bitlik verinin en yüksek biti 1'dir. Bu mantıksızdır, bu nedenle ilk veri CS düştüğünde ayarlanmalıdır. Tamam, sonra SCK'nın düşen kenarına ayarlayın, böylece 8 bitlik veriler mükemmel bir şekilde gönderilebilir!

// ----------------------------------- // her zaman @ çıktı (posedge clk veya negedge rst_n) eğer (! rst_n) txd_flag < = 1'b0; aksi takdirde txd_flag < = mcu_write_done; end

Son kısım txd_flag sinyalinin üretilmesidir.Çok basit olmasına rağmen yine de birkaç kelime söylemem gerekiyor.Neden aşağıdaki biçimde yazmıyorsunuz?

// ----------------------------------- // her zaman @ çıktı (posedge clk veya negedge rst_n) eğer (! rst_n) txd_flag < = 1'b0; else if (mcu_write_done) txd_flag < = 1'b1; aksi takdirde txd_flag < = 1'b0; son

Yukarıdaki kodda yazılan hiç bir problem yok ama özlü değil, bu yüzden birincisi tavsiye ediliyor.Aslında, yazarın anahtar geri dönüşünde ilk kullanım!

Sonuçta, her şey o kadar mükemmel ki, mükemmel zamanlama, mükemmel sonuç!

Çılgın Bitcoin, 10.000 yuan'ı yeni bir zirveye çıkararak geri döndü; Çin, dünyanın ilk 10 bit optik kuantum bilgisayarını piyasaya sürdü | Lei Feng Morning Post
önceki
Wang Dingguo Yoksulluğu Azaltma Vakfı, tüketimi ve yoksulluğu azaltmayı teşvik etmek için Linxian hünnap endüstrisini teftiş ediyor
Sonraki
Vibrato patladı ve bu şişe çay yağı acemi annenin 171. kazasını çözdü!
Bell, bu serginin en havalı ürünü olabilecek hava taksisi Nexus'u sergiliyor CES 2019
Basın toplantısı yine vurdu! Meizu ve Xiaomi ne zaman aşık olup birbirlerini öldürecek?
Yeni bir su seviyesi tespit sistemi türü
Zhang Xiaolong, WeChat'e geri dönüyor ve size ürün yapım metodolojisini anlatmak için 4 saat konuşma yapıyor Titanium Media 4D Record
MT8880 Çipin Android Tabanlı Tasarım ve Uygulaması
Tiyatro deminingi a Birkaç oyun izledikten sonra kırmızı gözlerle tiyatrodan çıktım
Netizenler pahalı diye bağırıyor: Mazda CX-8, Highlander'a yalnızca duygularla meydan okuyamaz
Hunan şarabının yeni geleceğine liderlik eden Liuyang Nehri, "yeni ünlü şarap" kralıyla geri dönüyor
CES New Products Confluence: Sergi resmi olarak açılıyor, bu yıl hangi teknolojiler kanat olacak? CES 2019
[2017 AI En İyi İşveren] seçimi için 30'dan fazla şirket kaydoldu, daha fazla şirketin katılmasını bekliyoruz
Xiaomi'nin acelesi var! Zhao Liying'in iyi haberi MIX3'ün momentumunu "yok etti" ve 5G konseptini kurtarmaya mı getirdi?
To Top