परिचय
डैलिनज ,
गुलिक और
होशी के पदों को देखने के बाद
, मुझे एक बार फिर लगा कि हबर एक केक है।
लिनक्स के लिए HD44780 पर आधारित चरित्र प्रदर्शन ड्राइवर लिखने वाला पहला पोस्ट (
dlinyj से
अपने खुद के लिनक्स ड्राइवर बनाना ); इसके उत्कृष्ट उत्तर अच्छे
हबीबर्स के पद थे (
गीक की शैली में बधाई, बिना जलाऊ लकड़ी के लेखन ) और
होशी (
नए साल की रसभरी - हम रास्पबेरी पाई को एचडी
44780 स्क्रीन को
उपवास करते हैं )।
मैं भी जीवन के इस उत्सव में भाग लेना चाहता था और अपने हार्डवेयर
vt52-like
टर्मिनल को लागू करना चाहता था। मेरे पास एक प्रतीकात्मक प्रदर्शन नहीं था, लेकिन एआरएम कोर्टेक्स-एम 3 पर आधारित एक चीनी देव-बोर्ड था, जिसमें पूर्ण 240x320 टीएफटी डिस्प्ले, आंशिक दस्तावेज थे।
उत्साह का भंडार था, इसलिए, रविवार दोपहर (~ 17 एमएसके) को जगाते हुए, मैंने इस एलसीडी के लिए एक एम्बेडेड ड्राइवर लिखना शुरू कर दिया।
यदि आप एम्बेडेड एआरएम प्रोग्रामिंग, इलेक्ट्रॉनिक्स, या सिर्फ परिणाम में रुचि रखते हैं - कृपया, बिल्ली के नीचे।
लोहा
मेरे निपटान में एक
एसटी STM32F103RB माइक्रोकंट्रोलर पर आधारित USB-UART
प्रोलिफिक PL-2303HX हार्डवेयर ब्रिज के साथ एक छोटा सा बाह्य उपकरणों का एक गुच्छा और एक अज्ञात कनेक्शन आरेख के साथ
Ilitek ILI9320 कंट्रोलर के साथ TFT TFT के साथ एक
साधारण डिबग बोर्ड था ।
इन-सर्किट डिबगर और प्रोग्रामर के रूप में,
ओलीमेक्स जेटीएजी एआरएम-टिनि-यूएसबी-एच का उपयोग किया गया था । एक अच्छा उपकरण, यह
OpenOCD के साथ ठीक काम करता है।
अधिक सटीक रूप से, शुरू में यह भी ज्ञात नहीं था कि एलसीडी पर किस तरह का नियंत्रक है। सब कुछ जो डिस्प्ले मॉड्यूल से सीखा जा सकता है कि यह 16-बिट बस के माध्यम से जुड़ा हुआ है जिसमें
nCS
,
nWR
,
nRD
,
BL_EN
और
RS
सिग्नल हैं।
जिसका उद्देश्य अनुमान लगाना मुश्किल नहीं था:
nCS
- प्रदर्शन बस की सक्रियता (इसके बाद उपसर्ग n
अर्थ है कि सक्रिय संकेत स्तर 0 है)BL_EN
- बैकलाइट नियंत्रणnWR
- रिकॉर्डnRD
- पढ़ाRS
- रजिस्टर चयन
इंटरनेट के चीनी खंड के विस्तार पर पाए जाने वाले प्रलेखन में से एक में, इसके साथ एक समान शुल्क था
इलीटेक 932x मॉड्यूल।
सॉफ्टवेयर इंटरफेस
निम्न स्तर का इंटरफ़ेस
चूंकि RuNet में इस एलसीडी नियंत्रक के साथ काम करने के कई विवरण नहीं हैं, मैं शायद निम्न-स्तरीय इंटरफ़ेस का वर्णन करूंगा।
इस नियंत्रक में अनिवार्य रूप से उनमें से 4 हैं: i80- प्रणाली (समानांतर इंटरफ़ेस, एक एचडी -7807 इंटरफ़ेस के समान समानांतर मेमोरी), SPI, VSYNC (सिस्टम +
VSYNC
, आंतरिक
VSYNC
के साथ) और RGB (
VSYNC
,
HSYNC
,
ENABLE
, बाहरी के साथ)
DOTCLK
टाइमिंग)। मेरे मामले में, i80- प्रणाली और, संभवतः, SPI (परीक्षण नहीं) उपलब्ध हैं।
चूंकि मैंने केवल प्रणाली का उपयोग किया है, हम इसके विवरण पर एक नज़र डालेंगे। लेख में बहुत अधिक लोड न करने के लिए - यह स्पॉइलर में होगा।
इलेक्ट्रिकल इंटरफ़ेस ILI9320विद्युत स्तर पर, डिजिटल तकनीक के साथ काम आमतौर पर समय आरेख द्वारा वर्णित किया जाता है। हमारे मामले में, पांच नियंत्रण संकेत और 16-बिट डेटा बस हैं।
nCS
को किसी भी जानकारी को प्रेषित करने से पहले, इंटरफ़ेस को
nCS
सिग्नल के साथ सक्रिय किया जाना चाहिए, इसे 0 पर सेट करना।
इसके अलावा, जब 0
RS
सेट किया जाता है, तो रजिस्टर का पता लिखा जाता है, जिसमें जानकारी दर्ज की जाएगी (वास्तविक रिकॉर्डिंग
nWR
सिग्नल को सक्रिय करके किया जाता है।
RS
सिग्नल 1 पर वापस सेट हो जाता है।
उसके बाद, वास्तविक रीड या राइट ऑपरेशन किया जाता है (क्रमशः
nRD
और
nWR
का उपयोग करके)।
इन प्रक्रियाओं के आरेख निम्नानुसार हैं:
सेशन | |
---|
पढ़ना |  |
लिखने |  |
GRAM से लिखते / पढ़ते समय, एक विशेष रजिस्टर
0x22
। इसके अलावा, नियंत्रक ऑटो-इंक्रीमेंट कर सकता है
GRAM पते, जो आपको क्रमिक रूप से इसकी सामग्री को पढ़ने / लिखने की अनुमति देते हैं।
चित्र:
सेशन | |
---|
GRAM पढ़ा |  |
ग्राम लेखन |  |
ऑपरेशन पूरा करने के बाद,
nCS
वापस 1 पर सेट किया जाता है।
टाइमिंग आरेखों को खींचने के लिए, मुझे एक अद्भुत
वेवड्रोम परियोजना मिली जो एक ब्राउज़र में काम करती है।
यहां परीक्षण (ऊपर दिए गए चित्र यहां तैयार किए गए थे)।
विद्युत इंटरफ़ेस के आधार पर, निम्न-स्तरीय फ़ंक्शन लिखे गए थे:
lcd_ll_funcs void _lcd_select(void) { GPIO_ResetBits(GPIOC, GPIO_Pin_9); } void _lcd_deselect(void) { GPIO_SetBits(GPIOC, GPIO_Pin_9); } void _lcd_rs_set(void) { GPIO_SetBits(GPIOC, GPIO_Pin_8); } void _lcd_rs_reset(void) { GPIO_ResetBits(GPIOC, GPIO_Pin_8); } void _lcd_rd_en(void) { GPIO_ResetBits(GPIOC, GPIO_Pin_11); } void _lcd_rd_dis(void) { GPIO_SetBits(GPIOC, GPIO_Pin_11); } void _lcd_wr_en(void) { GPIO_ResetBits(GPIOC, GPIO_Pin_10); } void _lcd_wr_dis(void) { GPIO_SetBits(GPIOC, GPIO_Pin_10); } void _lcd_bl_en(void) { GPIO_SetBits(GPIOC, GPIO_Pin_12); } void _lcd_bl_dis(void) { GPIO_ResetBits(GPIOC, GPIO_Pin_12); }
तेजी लाने के लिए, आप इन कार्यों को इनलाइन कर सकते हैं और उन्हें मैक्रोज़ में बदल सकते हैं (जिसके साथ ग्रहण बहुत अनुकूल नहीं है, दुर्भाग्य से)।
इन कार्यों के आधार पर, रजिस्टर में लिखने के लिए, रजिस्टर से पढ़ने के लिए, और इमेज ब्लिटिंग के लिए कार्य कार्यान्वित किए जाते हैं।
उच्च स्तरीय इंटरफ़ेस
कार्यक्रम के मुख्य भाग के लिए एलसीडी फ़ंक्शन निम्नलिखित एपीआई के माध्यम से उपलब्ध हैं:
u16 lcd_init(void); void lcd_set_cursor(u16 x, u16 y); void lcd_set_window(u16 left, u16 top, u16 right, u16 bottom); void lcd_fill(u32 color); void lcd_rect(u16 left, u16 top, u16 right, u16 bottom); void lcd_put_char_at(u32 data, u16 x, u16 y); u32 lcd_get_fg(void); u32 lcd_get_bg(void); void lcd_set_fg(u32 color); void lcd_set_bg(u32 color);
टर्मिनल फ़ंक्शंस इस इंटरफ़ेस का उपयोग उनके सभी कार्यों के लिए करते हैं।
सबसे दिलचस्प हिस्सा एक प्रतीक को खींचने का कार्य है, क्योंकि फोंट के साथ सभी काम इसके पीछे छिपे हुए हैं। यह इस तरह दिखता है:
lcd_put_char_at void lcd_put_char_at(u32 data, u16 x, u16 y) { u8 xsize, ysize; u8 *char_img; lcd_get_char(data, &xsize, &ysize, &char_img); lcd_set_cursor(x, y); lcd_set_window(x, y, x + xsize, y + ysize); _lcd_select(); _lcd_tx_reg(0x22);
जैसा कि आप देख सकते हैं, प्रतीक बिटमैप और उसके आकार का लिंक प्रतीक कोड द्वारा
lcd_get_char
फ़ंक्शन से आता है (यह 32-बिट है ताकि अतिरिक्त वर्णों के साथ ASCII भाग को स्पर्श न करें)।
वर्तमान में, एक फ़ॉन्ट का उपयोग किया जाता है जिसमें ASCII तालिका के नीचे, प्लस "हेरिंगबोन" होता है। जो लोग इसे खोजने की कोशिश कर सकते हैं)
सबसे कम दिलचस्प और सबसे महंगा (लेखन समय के संदर्भ में) प्रदर्शन आरंभीकरण समारोह है:
lcd_init: उन लोगों के लिए जो डरना चाहते हैं u16 lcd_init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitTypeDef gpio_conf; gpio_conf.GPIO_Speed = GPIO_Speed_50MHz; gpio_conf.GPIO_Mode = GPIO_Mode_Out_PP; gpio_conf.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12; GPIO_Init(GPIOC, &gpio_conf); lcd_gpio_conf(GPIO_Mode_Out_PP);
टर्मिनल कार्यान्वयन
यह हिस्सा अचूक है। पिछले लेखों में से कुछ कोड के साथ एक अनफिल्ड टर्मिनल लागू किया गया है।
क्रम से बचोपलायन क्रम:
- \ 033 [ए = कर्सर को एक पंक्ति ऊपर ले जाएं
- \ 033 [बी = कर्सर को एक पंक्ति नीचे ले जाएं
- \ 033 [C = कर्सर को दाईं ओर ले जाएं
- \ 033 [डी = कर्सर को बाईं ओर एक स्थिति में ले जाएँ
- \ 033 [H = कर्सर को ऊपरी बाएँ कोने में ले जाएँ - घर (स्थिति 0,0)
- \ 033 [जे = सब कुछ साफ़ करें, कर्सर घर वापस न करें!
- \ 033 [K = पंक्ति के अंत में मिटाता है, कर्सर को घर नहीं लौटाता है!
- \ 033 [एम = नया चरित्र मानचित्र - कार्यान्वित नहीं किया गया
- \ 033 [Y = स्थिति, YX लेता है
- \ 033 [X = स्थिति, XY लेता है
- \ 033 [R = CGRAM मेमोरी सेल चयन - लागू नहीं, क्योंकि कोई CGRAM नहीं
- \ 033 [वी = स्क्रॉलिंग सक्षम - कार्यान्वित नहीं
- \ 033 [डब्ल्यू = स्क्रॉलिंग अक्षम - लागू नहीं
- \ 033 [बी = बैकलाइट चालू / बंद - लागू नहीं
अन्य उपयोगी कोड:
- \ r = कैरिज रिटर्न (वर्तमान लाइन पर कर्सर को स्थिति 0 पर लौटाएं!)
- \ n = नई पंक्ति
- \ t = टैब (डिफ़ॉल्ट 3 वर्ण)
संचार
बाहरी दुनिया के साथ बातचीत करने के लिए,
USART1
उपयोग यूएसबी
PL-2303HX
UART
PL-2303HX
माध्यम से अतुल्यकालिक मोड में किया जाता है।
लिनक्स होस्ट के नजरिए से, यह
/dev/ttyUSBx
। दुर्भाग्य से,
pl2303
लिए ड्राइवर बल्कि अस्थिर थे। लेकिन, जैसे ही वे उठाते हैं, वे शालीनता से काम करते हैं।
मुख्य लूप (जो खाली है) में यूएआरटी को प्रदूषित नहीं करने के लिए, इसके साथ काम इंटरप्ट पर लागू किया जाता है।
सॉफ़्टवेयर के दृष्टिकोण से, इसका मतलब है कि USART1 को प्रारंभ करने के बाद, आपको NVIC में संबंधित इंटरप्ट वेक्टर को कॉन्फ़िगर करना होगा।
यह इस तरह दिखता है:
NVIC_InitTypeDef nvic_conf; nvic_conf.NVIC_IRQChannel = USART1_IRQn; nvic_conf.NVIC_IRQChannelPreemptionPriority = 0; nvic_conf.NVIC_IRQChannelSubPriority = 2; nvic_conf.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&nvic_conf); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
अंतिम कमांड रिसेप्शन रजिस्टर USART1 में भरने की घटना को हल करता है।
तदनुसार, प्रसंस्करण इस तरह दिखता है:
void USART1_IRQHandler(void) { u8 data = USART1->DR; uart_write_byte(data); handle_byte(data); }
बाइट बैक (ईको) भेजें और हैंडलर को कॉल करें, जो एक साधारण स्टेट मशीन है।
सभी कोड
github रिपॉजिटरी में प्रकाशित हुआ है।
पुनश्च
इस पोस्ट को लिखने में लगभग 6 घंटे लगे। हार्डवेयर और सॉफ्टवेयर भागों को लिखना और डिबग करना - लगभग 13 घंटे।
इसे पढ़ने वाले सभी को धन्यवाद। सभी स्लग और अन्य कीड़ों के बारे में, एक व्यक्तिगत में लिखें।