DCMI के माध्यम से समानांतर ADC से STM32F4xx में डेटा प्रविष्टि

यह ज्ञात है कि STM32F4xx माइक्रोकंट्रोलर परिवार, जिसके पास पर्याप्त रूप से उत्पादक कोर हैं, जो "नॉन-मीट-कटिंग" कार्यों के लिए काफी उपयुक्त हैं, डीएसपी के पास "पाइप-लाइन" (clk-data) मोड में सरल समानांतर बस के साथ एक पूर्ण डेटा इनपुट इंटरफ़ेस नहीं है। स्मोक्ड dm00037051.pdf के बाद, मुझे एक गैर-विशिष्ट मिला, लेकिन पहली नज़र में, उपयुक्त विकल्प - DCMI (डिजिटल कैमरा इंटरफ़ेस) इंटरफ़ेस।

बेशक, एक लोडेड क्लासिक डीएसपी (एफआईआर, आईआईआर, एफएफटी) के लिए एसटीएम 32 माइक्रोकंट्रोलर्स का उपयोग एक इष्टतम विकल्प नहीं है, लेकिन अगर कार्ड अचानक लेट गए और अभी भी इस माइक्रोकंट्रोलर की क्षमताएं पर्याप्त हैं, तो आपको कम गति वाले इंटरफेस की पर्याप्त संख्या की आवश्यकता है। इसके बारे में कटौती के तहत।





"हॉट" डेडलाइन और बजट के साथ एक प्रोजेक्ट पर, इष्टतम लोगों के साथ "लोहे का एक टुकड़ा" लागू करने की आवश्यकता थी: द्रव्यमान, आयाम, खपत। एक मूल कार्य के रूप में, डिजिटल सिग्नल प्रोसेसिंग (फ़िल्टरिंग और स्टेटिस्टिकल एनालिसिस), सॉफ्ट रीयल-टाइम मोड में एडीसी से आने के लिए आवश्यक था। प्रसंस्करण के लिए, मैं एक एकल सटीक फ्लोटिंग पॉइंट रखना चाहता था। एडीसी से संकेत 48 मेगाहर्ट्ज की एक मध्यवर्ती आवृत्ति पर प्राप्त हुआ था। 1 मेगाहर्ट्ज सिग्नल बैंड। मध्यवर्ती आवृत्ति से शून्य तक सिग्नल के स्पेक्ट्रम के हस्तांतरण को लागू करने के लिए, अधिमानतः ब्रॉडबैंड एडीसी की सबसामलिंग का उपयोग करना। इसके अलावा, ईथरनेट, एसपीआई, UART, I2C के माध्यम से जानकारी प्राप्त करना और संचारित करना और व्यवधानों के साथ काम करना आवश्यक था।


कार्यान्वयन की समय सीमा और विशिष्ट डीएसपी कार्यों ने इन उद्देश्यों के लिए FPGAs के उपयोग की अनुमति नहीं दी। ब्लैकफिन परिवार के प्रसिद्ध सिग्नल प्रोसेसर के साथ, प्रसिद्ध एनालॉग डिवाइसेस के पास कोई संचार अनुभव नहीं था और निकट पहुंच में डिबगिंग टूल और डेमो बोर्ड नहीं थे। एक बार प्रमुख DSP प्रोसेसर ADSP-TS201 TigerSHARC, महंगे के साथ घनिष्ठ और लंबे संचार का अनुभव था। इसके अलावा, ब्लैकफिन में IEEE-754 के हार्डवेयर कार्यान्वयन का अभाव है। इसके अलावा, 128 केबी के एडीसी के साथ डेटा के एक निरंतर ब्लॉक को स्वीकार करना आवश्यक था, साथ ही ओवरहेड प्रसंस्करण के 30 केबी और बाहरी मेमोरी के बिना कुछ कम बजट में सब कुछ अलग करना मुश्किल था।


सामान्य तौर पर, केवल STM32F407 बोर्ड (डिस्कवरी और चीन से कस्टम) थे। जैसा कि मुझे संदेह है, कई जो संबंधित विषयों से निपटते हैं, अब उनके पास इस तरह की सार्वभौमिक मदद है। एक टेरासिक एडीए-एचएसएमसी बोर्ड भी था जिस पर AD9228 दोहरे चैनल एडीसी स्थापित किया गया था (12-बिट, एफडी = 65 एमएसपीएस, बैंडविड्थ = 315 मेगाहर्ट्ज)।


एक गैर-विशिष्ट, लेकिन काफी उपयुक्त विकल्प डीसीएमआई (डिजिटल कैमरा इंटरफ़ेस) इंटरफ़ेस है, जिसे एसटीएम 32 एफ 4 में लागू किया गया है।


इस इंटरफ़ेस का संचालन RM0090, DocID018909, पृष्ठ 454/1718 में वर्णित है। इस दस्तावेज़ से निम्नलिखित चार आंकड़े दिए गए हैं।


तो, दावा किया गया इनपुट आवृत्ति 54 मेगाहर्ट्ज तक है। जो काफी पर्याप्त है - हमारी उप-नमूना दर 10 मेगाहर्ट्ज है। यहाँ DCMI इंटरफ़ेस संकेतों का उपयोग किया जाता है:





नोट: D13, D14 केवल 144-पिन पैकेज में उपलब्ध हैं। हमारे पास 100-पिन है, लेकिन हमें उनकी आवश्यकता नहीं है। (हालांकि एनालॉग डिवाइसेज में समान 14 बिट ADC - AD9248 है)।


यहाँ इंटरफ़ेस का एक सामान्यीकृत समय आरेख है:





और यह JPEG फ्रेम प्रारूप मोड में इंटरफ़ेस का समय आरेख है:





हम इस ऑपरेटिंग मोड का उपयोग करेंगे वह हमें सबसे अच्छा लगता है।


इस मोड में, वीएसवाईएनसी सिग्नल को शक्ति में खींच लिया जाता है। हम इंटरफ़ेस के माध्यम से डेटा रिसेप्शन की शुरुआत को सक्षम करने के लिए बाहरी संकेत के रूप में HSYNC का उपयोग करेंगे।


हमने LQFP100 पैकेज में STM32F407RGT6 माइक्रोकंट्रोलर का उपयोग किया।


AD9238 ADC में संबंधित चैनल PDWN_A (B) के शटडाउन (पावर सेविंग) मोड के लिए एक इनपुट है, और आउटपुट अनुमति OEB_A (B) है। उन्हें किसी भी नियंत्रक पिन से प्राप्त करना तर्कसंगत है। परिणामस्वरूप, पिन कनेक्शन आरेख इस तरह दिखाई देगा:



चूँकि इस ADC में आउटपुट क्लॉक सिग्नल नहीं है, इसलिए मल्टीप्लाई (घड़ी बफर) का उपयोग करना आवश्यक है। हमने टेक्सास इंस्ट्रूमेंट्स से LMK00101 का इस्तेमाल किया - कीमत के लिए अच्छा मूल्य, कम घबराना, और सबसे महत्वपूर्ण, फिर से - हाथ में)।


प्रसंस्करण में, हम इस बात को ध्यान में रखते हैं कि इनपुट घड़ी सिग्नल के सापेक्ष ADC समानांतर बस पर डेटा 7 घड़ी चक्रों की देरी के साथ दिखाई देता है।


हम डीएमए के माध्यम से डेटा (निश्चित रूप से) प्राप्त करेंगे। यहाँ DCMI और DMA को इनिशियलाइज़ करने के लिए सोर्स कोड दिया गया है।


हम उन पोर्ट की क्लॉकिंग को चालू करते हैं जिनकी हमें आवश्यकता है, DCMI और DMA2


GPIO_InitTypeDef GPIO_InitStructure; /* Enable DCMI GPIOs clocks */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOD, ENABLE); /* Enable DCMI clock */ RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_DCMI, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); 

यह पिन (PA5) विभाजन को तख्ते में बदल देगा - HSYNC। बाहर निकलने पर प्रारंभिक


  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_ResetBits(GPIOA, GPIO_Pin_5); //HSYNC_PA4 -PA5 -> GND 

DCMI मोड में संबंधित पिन कॉन्फ़िगर करें


  /* PCLK */ GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_DCMI); /* D0-D7 */ GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_DCMI); //D0* GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_DCMI); //D1* GPIO_PinAFConfig(GPIOC, GPIO_PinSource8, GPIO_AF_DCMI); //D2* GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_DCMI); //D3* GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_DCMI); //D4* GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_DCMI); //D5* GPIO_PinAFConfig(GPIOE, GPIO_PinSource5, GPIO_AF_DCMI); //D6* GPIO_PinAFConfig(GPIOE, GPIO_PinSource6, GPIO_AF_DCMI); //D7* GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_DCMI); //D8* GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_DCMI); //D9* GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_DCMI); //D10* GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_DCMI); //D11* /* VSYNC */ GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_DCMI); /* HSYNC */ GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_DCMI); /* DCMI GPIO configuration **************************************************/ /* D0,D1,D2,D3,D4,D8,D9 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ; GPIO_Init(GPIOC, &GPIO_InitStructure); /* D6,D7*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6; GPIO_Init(GPIOE, &GPIO_InitStructure); /* D10, D5, VSYNC(PB7) */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; GPIO_Init(GPIOB, &GPIO_InitStructure); /* D11(PD2) */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_Init(GPIOD, &GPIO_InitStructure); /* PCLK(PA6) HSYNC(PA4)*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_6; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); 

यहां सबसे दिलचस्प बात यह है कि जेपीईजी फ्रेम के अनुरूप मोड में डीसीएमआई को कॉन्फ़िगर करना है।


  DCMI_InitStructure.DCMI_CaptureMode = DCMI_CaptureMode_Continuous; DCMI_InitStructure.DCMI_SynchroMode = DCMI_SynchroMode_Embedded; DCMI_InitStructure.DCMI_PCKPolarity = DCMI_PCKPolarity_Rising; DCMI_InitStructure.DCMI_VSPolarity = DCMI_VSPolarity_Low; DCMI_InitStructure.DCMI_HSPolarity = DCMI_HSPolarity_High; DCMI_InitStructure.DCMI_CaptureRate = DCMI_CaptureRate_All_Frame; DCMI_InitStructure.DCMI_ExtendedDataMode = DCMI_ExtendedDataMode_12b; 

डीएमए सेटअप


  DCMI_Init(&DCMI_InitStructure); DMA_InitStructure.DMA_Channel = DMA_Channel_1; DMA_InitStructure.DMA_PeripheralBaseAddr = DCMI_DR_ADDRESS; //0x50050028 DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)DCMI_PendingData; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStructure.DMA_BufferSize = MAX_DOWBLE_BUF; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA2_Stream1, &DMA_InitStructure); 

संबंधित डीएमए चैनल से डेटा प्राप्त करने के अंत में व्यवधान डालना


  NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 

हमारे हैंडलर का कोड, जिसमें हम DCMI डेटा रिसेप्शन को बंद कर देते हैं और डेटा रेडी फ्लैग सेट करते हैं।


 void EXTI1_IRQHandler() { EXTI_ClearFlag(EXTI_Line1); DMA_ClearITPendingBit(DMA2_Stream1, DMA_IT_TCIF1); DMA_Cmd(DMA2_Stream1, DISABLE); DCMI_Cmd(DISABLE); dma_recv_f = 1; //GPIO_ResetBits(GPIOE, GPIO_Pin_0); //VSYNC reset } 

सब कुछ सेटिंग्स के साथ है। अब हम अपने डीएमए चैनल, डीसीएमआई ब्लॉक को चालू करते हैं, हम जेपीईजी फ्रेम मोड में डीसीएमआई डेटा प्राप्त करना शुरू करते हैं।


  /* Enable DMA transfer */ DMA_Cmd(DMA2_Stream1, ENABLE); /* Enable DCMI interface */ DCMI_Cmd(ENABLE); /* Start Image capture */ DCMI_CaptureCmd(ENABLE); DCMI_JPEGCmd(ENABLE); 

मुख्य कार्यक्रम का चक्र। यहां, ध्वज को मतदान करना और डेटा रिसेप्शन को फिर से शुरू करना।


 uint8_t dma_recv_f = 0; //,     . uint16_t DCMI_PendingData[8500]; //    DCMI int main(void) { DCMI_Config(); //        __enable_irq(); //  while(1) { while(dma_recv_f!=1){}; //    dma_recv_f = 0; //  /*     */ Re_DMA_Config(DCMI_PendingData, glob_cnt); // DMA } } 

नोट: यदि आपको डबल बफ़रिंग के साथ कठिन वास्तविक समय में डेटा प्राप्त करने और संसाधित करने की आवश्यकता है, तो stm32f4 में एक बाधा तंत्र होता है जब आधा बफर भरा होता है। डीएमए सेटिंग्स में तो डेटा रिसेप्शन के निरंतर चक्रीय मोड को सेट करना आवश्यक है। उदाहरण के लिए:


  // DMA2 Stream0 channel0 configuration ************************************** DMA_InitStructure.DMA_Channel = DMA_Channel_1; DMA_InitStructure.DMA_PeripheralBaseAddr = DCMI_DR_ADDRESS; //0x50050028 DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)DCMI_PendingData; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_BufferSize = buf_size; <b>DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;</b> //     DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable; <b>DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;</b> //  DMA     DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; 

इंटरप्ट हैंडलर में, फिर संपूर्ण बफर को भरने के बाद ही डीएमए एंड बिट को रीसेट करना आवश्यक है, और उपयोगकर्ता प्रोग्राम वर्तमान बफर की संख्या को इंगित करने के लिए जिसमें डेटा रिसेप्शन समाप्त हो गया है। कुछ इस तरह:


 if(DMA_GetITStatus(DMA2_Stream1,DMA_IT_TCIF1)){ DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF1); num_buf = 1; } else{ num_buf = 0; } 

यह मूल रूप से DCMI के माध्यम से हमारे ADC से डेटा प्राप्त करने के लिए आवश्यक है।


दुर्भाग्य से, इस समय मैं इस पूरे तंत्र को लाइव प्रदर्शित नहीं कर सकता। लोहे का टुकड़ा पहले से ही ऑपरेशन में लगभग 3 साल है)))। मैं केवल उन समय से सहेजे गए परीक्षण पंजीकरण डेटा ला सकता हूं।


यहाँ SMB100A जनरेटर से 48.001 मेगाहर्ट्ज की आवृत्ति पर एक हार्मोनिक संकेत है, 1 IFHz ऑफसेट के साथ हमारे IF के बराबर है:





और यह इसका स्पेक्ट्रम है:





लगभग 200 मिमी की लंबाई के साथ मानक ब्रेडबोर्ड तारों पर अधिकतम प्रदर्शन की जांच करने के लिए, जिसके साथ एडीए-एचएसएमसी और एसटीएम 32 एफ 4 डिस्कवरी जुड़े हुए थे, सही डेटा 40 मेगाहर्ट्ज की घड़ी आवृत्ति पर प्राप्त हुए थे।
इस कार्य के लिए निर्मित "देशी" बोर्ड पर, एक फ्लैट केबल के माध्यम से, 100 मिमी लंबे, कमरे के तापमान पर, यह नमूना आवृत्ति को अधिकतम 54 मेगाहर्ट्ज तक बढ़ाने के लिए निकला।
10 मेगाहर्ट्ज के वांछित नमूने की आवृत्ति पर, औद्योगिक रेंज पर प्रदर्शन का परीक्षण किया गया: -40 से +60 तक।


वास्तव में सब कुछ। आपका ध्यान के लिए धन्यवाद!




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


All Articles