Bagaimana mikrokontroler dapat membaca data pada 1,6 Gbps

Hari baik untuk semua! itu tidak pernah terjadi dan di sini lagi . Cukup waktu telah berlalu sejak artikel terakhir saya, dan itu menimbulkan tantangan baru. Dan jika saya dulu mentransfer data pada kecepatan 100 Mbps, sekarang saya harus mengayun di 1600 Mbps ...

Di KDPV - pahlawan novel kami - ia bisa membaca data dengan kecepatan seperti itu!



Jadi, proyek saya berikutnya menuntut untuk membaca aliran data 32-bit pada kecepatan 50 MHz (ini, omong-omong, akan menjadi 1,6 Gbps yang sama) dalam jumlah yang diketahui sebelumnya - biarlah 10.000. Akan baik-baik saja untuk segera membaca menggunakan DMA dari satu port - tetapi, sayangnya, tidak ada prosesor yang sesuai (saya harap seseorang memperbaiki masalah ini di komentar), untuk beberapa alasan, semua port yang cocok untuk kecepatan adalah karena alasan 16-bit.

Tapi hal sepele seperti itu tidak akan menghentikan kita - kita akan membaca dari dua port sekaligus! Benar, ini dalam kasus umum tidak akan selalu mungkin dilakukan dengan tingkat kontrol dan sinkronisasi yang diperlukan, tetapi dalam kasus kami, semuanya tidak begitu menyedihkan - ada sinyal setelah data 20 ns akan disimpan di port.

Dan karena prosesor yang kami miliki adalah stm32h750 pada 400 MHz, dan bus dan timer pada 200 MHz, maka semuanya akan berjalan dengan baik.

Tampaknya kasus sederhana - untuk memicu penerusan DMA tunggal pada sinyal. Tetapi hanya DMA yang tidak memiliki kesempatan seperti itu - port dapat mengeluarkan interupsi, tetapi tidak dapat mengontrol DMA. Tetapi prosesor kami memiliki hal yang baik - DMAMUX, di mana ada generator acara untuk saluran DMA, tetapi generator ini memiliki dua opsi yang sesuai - baik menggunakan interupsi EXTIT0 atau sinyal dari timer TIM12 (pengembang chip memiliki fantasi aneh).

Kami tidak punya waktu untuk gangguan - kami bahkan membutuhkan sekitar 47 siklus jam untuk bekerja kosong, dan siklus clock kami adalah 2,5 ...

Tetapi pada waktunya untuk timer. Tetap hanya untuk memasang timer dari sinyal eksternal 100 MHz, dan mengatur panjang timer ke 1 dan output TRGO akan memicu generator DMAMUX, dan kemudian akan mengeluarkan perintah untuk mengirim DMA dan akan membaca port dan mengirim data ke memori.

Tapi berhentilah! Port-nya adalah 16-bit, tetapi kami memiliki 32 ... Nah, Anda dapat mencoba membaca port kedua yang lain ... Hanya untuk ini kami membutuhkan saluran DMA kedua, dan akan menggunakan bus yang sama - yaitu, kami akan memiliki waktu untuk membaca, tetapi kami dapat tidak punya waktu untuk menulis data ke memori. Nah, secara teoritis, prosesor ini memiliki berbagai jenis memori, dan dalam gambar besar struktur prosesor Anda dapat melihat bahwa memori DMA dan RAM_D1 duduk di bus yang sama dengan frekuensi 200 MHz. Masih memverifikasi dalam praktek.

DMA1->LIFCR |= ~0; DMA1_Stream0->CR = (0b11 << DMA_SxCR_PL_Pos) | (0b01 << DMA_SxCR_MSIZE_Pos) | (0b01 << DMA_SxCR_PSIZE_Pos) | DMA_SxCR_MINC; DMA1_Stream0->M0AR = (uint32_t) data; DMA1_Stream0->PAR = (uint32_t) &(GPIOE->IDR); DMA1_Stream0->NDTR = 10000; DMA1_Stream1->CR = (0b11 << DMA_SxCR_PL_Pos) | (0b01 << DMA_SxCR_MSIZE_Pos) | (0b01 << DMA_SxCR_PSIZE_Pos) | DMA_SxCR_MINC; DMA1_Stream1->M0AR = (uint32_t) data2; DMA1_Stream1->PAR = (uint32_t) &(GPIOD->IDR); DMA1_Stream1->NDTR = 10000; DMAMUX1_Channel0->CCR = DMAMUX_CxCR_EGE | (1); DMAMUX1_Channel1->CCR = DMAMUX_CxCR_EGE | (2); DMAMUX1_RequestGenerator0->RGCR = DMAMUX_RGxCR_GE | (0b01 << DMAMUX_RGxCR_GPOL_Pos) | (7); DMAMUX1_RequestGenerator1->RGCR = DMAMUX_RGxCR_GE | (0b01 << DMAMUX_RGxCR_GPOL_Pos) | (7); DMA1_Stream0->CR |= DMA_SxCR_EN; DMA1_Stream1->CR |= DMA_SxCR_EN; TIM12->CNT = 0; TIM12->CCMR1 |= TIM_CCMR1_CC2S_0; TIM12->CR2 = (0b010 << TIM_CR2_MMS_Pos); TIM12->CR1 |= TIM_CR1_CEN; while (DMA1_Stream0->NDTR) i++; TIM12->CR1 &= ~TIM_CR1_CEN; 

Dan tentu saja, Anda perlu menempatkan data dan array data2 di segmen memori yang diinginkan, ini dilakukan seperti ini:

 __attribute__((section(".dma_buffer"))) uint16_t data[10240],data2[10240]; 

dan dalam file untuk tautan menunjukkan:

 .dma_buffer : { *(.dma_buffer) } >RAM_D1 

Untuk memeriksa, yah, dan sebagai opsi pertama, hanya penyalinan bodoh diimplementasikan menggunakan
CPU (masih 400 MHz):

  uint16_t * ptr = cpudata; volatile uint16_t * src = &(GPIOE->IDR); volatile uint16_t * src2 = &(GPIOD->IDR); for (register int i = 0; i < 10000; i++) { *ptr++ = *src; *ptr++ = *src2; } 

Untuk verifikasi, data cpudata terletak di memori yang berbeda, yang tercepat (well, memang benar, hanya 64K) adalah memori tercepat (juga 400 MHz) DTCMRAM.

Hasil


Selama pengujian, ternyata dengan bantuan CPU dimungkinkan membaca pada kecepatan 12,5 MHz dari dua port. Dan 25 MHz dari satu. Jadi opsinya tidak berfungsi ...

Dengan bantuan DMA dan ibu seperti itu, TIM12 berhasil membaca pada kecepatan 50 MHz, dan dalam beberapa jam tidak ada tes kesalahan tunggal. Kedua port dibaca, tetapi masih belum memungkinkan untuk mengukur seberapa jauh pembacaan pada DMA kedua tertinggal ...

Jadi dalam kasus saya (sedikit merosot), saya berhasil mencapai kecepatan transfer informasi ke prosesor stm32h750 pada kecepatan 32x50 = 1600 Mbps.

Source: https://habr.com/ru/post/id467459/


All Articles