قم بتوصيل شاشة ER-TFT101-1 بحجم 10 بوصات بـ STM32F429 عبر FMC

يوم جيد للجميع. في هذه المقالة ، سنقوم بتحليل اتصال شاشة TFT ER-TFT101-1 (10 بوصات ، RA8876) بلوحة STM32F429L Discovery عبر واجهة متوازية 8080 بت 16 بت باستخدام وحدة FMC (وحدة تحكم مرنة في الذاكرة).




حول عرض التجمع


ER-TFT101-1 من EastRising عبارة عن مجموعة من مصفوفة TFT مقاس 10 بوصة بدقة 1024 × 600 ولوحة مع برنامج تشغيل RA8876. تحتوي اللوحة المزودة ببرنامج التشغيل على كافة مصادر الطاقة اللازمة ، وتبلغ ذاكرة SD-RAM 16 ميجابايت (ناقل 16 بت ، و 166 MHz كحد أقصى ، و 64 ميجابايت كحد أقصى للسعة) ، وهناك فتحة لبطاقة microSD قياسية. هناك آثار أقدام فارغة تحت EEPROM مع خطوط خارجية وتحت ذاكرة فلاش للصور مع موصلات الإخراج لبرمجة لهم. أيضًا ، يمكن تثبيت لوحة اللمس المقاومة أو بالسعة اختياريًا على المجموعة.

على اللوحة ، يوجد برنامج RAiO RA8876 المتطور ذو تردد تشغيل يبلغ 120 ميجاهرتز ، والذي ، إذا رغبت في ذلك ، يمكن أن يعمل هو نفسه متحكم تحكم. يمكنك كتابة برنامج صغير (12 تعليمات فقط) ووضعه في ذاكرة فلاش خارجية. عند بدء تشغيل العرض ، سيبدأ هذا البرنامج في التشغيل في المقام الأول ، مكررة أساسًا جميع خيارات التحكم من خلال الواجهة الخارجية.



لا يحتوي RA8876 على ذاكرة الوصول العشوائي الخاصة به ، وبالتالي يستخدم ذاكرة SD-RAM خارجية. يمكنه قراءة الصور من ذاكرة الفلاش باستخدام DMA وتحميلها في إطارها المؤقت ويحتوي على تكوين مرن للغاية. يتم توصيل برنامج التشغيل بالمصفوفة نفسها باستخدام واجهة RGB قياسية بعرض 18 بت. يتم استخدام 6 بت فقط لكل قناة حمراء و 6 بت لكل قناة خضراء و 6 بت باللون الأزرق. لا يتم استخدام بت اثنين من كل قناة ، والذي يعطي من الناحية النظرية 262144 لونًا.

تشبه وحدة DMA الخاصة بـ RA8876 طراز DMA2D الخاص بـ STM - حيث يمكنها نسخ مقاطع مستطيلة من الذاكرة من مكان إلى آخر ، مع تحويل اللون والشفافية وشرائح أخرى.

يحتوي RA8876 أيضًا على خطوط باللغة الإنجليزية والصينية مضمنة (8 × 16 ، 12 × 24 ، 16 × 32 بكسل) مع إعدادات مرنة لعرضها (التدوير ، المقياس ، إلخ) وواجهة مصفوفة منفصلة (5 × 5) لأزرار الأجهزة (من أجل قائمة بذاتها و لا تستخدم فقط) مع مجموعة من الإعدادات ، مثل الضغط لفترة طويلة وقصيرة ، تستيقظ على الشاشة عن طريق الضغط على زر والضغط على عدة أزرار في نفس الوقت.

هناك وظيفة صورة في صورة (بدون دعم الشفافية) لعرض أي نوافذ منبثقة وقوائم.

يمكن للسائق نفسه أن يرسم بدائل رسومية ، مثل المربع ، الدائرة ، المنحنى ، البيضاوي ، المثلث ، مربع مستدير ، مع وبدون تعبئة. بالمناسبة ، في RA8875 و RA8876 يوجد خطأ صغير لملء المثلث ، ولكل سائق خاص به. لكن RAiO لم تعطِ الكلمة من برج الجرس المرتفع ... حاولت أن أكتب خطابًا إليهم بطريقة ما ، حتى أنهم لم يردوا. يتيح لك رسم هذه العناصر الأولية إنشاء رسومات جميلة حتى مع وجود متحكم بطيء.

مع العالم الخارجي ، يتصل RA8876 من خلال واجهات 8080/6800 8/16 بت و 3/4 أسلاك SPI و I2C. علاوة على ذلك ، يمكن لرقاقة السائق نفسها أن تكون بمثابة SPI و I2C. في RA8876 ، يوجد مخرجات PWM يمكن استخدامها للتحكم المرن في الإضاءة الخلفية. يتم الإعلان عن الحد الأقصى لتردد SPI CLK عند 66 ميجا هرتز مع تردد تشغيل قدره 120 ميجاهرتز ، والذي يعطي نظريًا 6 إطارات في الثانية من تحديث ملء الشاشة (عند 1024 × 600 × 16 بت). تم اختبار هذا الاتصال بواسطتي وأظهر أنه يتمتع بالحق في الحياة إذا لم نعرض الفيديو على الشاشة.

في حالتنا ، سنقوم بتوصيل الشاشة باستخدام بروتوكول 8080 بعرض 16 بت إلى STM32F429ZIT6 عبر وحدة FMC (وحدة تحكم مرنة في الذاكرة) ، مما سيتيح لنا الحصول على المزيد من سرعة ملء الشاشة وتحميل أقل على متحكم دقيق.

تكوين دبابيس 8080 و FMC


سننظر إلى مخطط الاتصال لـ 8080 في ورقة البيانات على الشاشة:



ننظر إلى المسامير اللازمة للاتصال بـ STM32 في CubeMX. نحن مهتمون بالمصرف رقم 1 (NOR Flash / PSRAM / SRAM / ROM / LDC 1).



بخصوص XnWAIT في ورقة البيانات ، يمكنك قراءة ما يلي:
تحدد سرعة كتابة البيانات المستمرة سرعة تحديث الشاشة. يجب أن يكون الفاصل الزمني من دورة إلى دورة أكبر من 5 من فترة ساعة النظام إذا كان المستخدم دون اعتماد XnWait لإدراج حالة الانتظار. قد يؤدي الإفراط في المواصفات إلى فقد البيانات أو فشل الوظيفة في حالة عدم استخدام آلية xnwait.
حرفيًا ، بين دورات تشغيل بروتوكول 8080 ، يجب إدخال تأخير من 5 أجسام نظام RA8876 إذا كان المستخدم لا يستخدم آلية XnWAIT لانتظار إصدار RA8876. سوف نستخدم هذا دبوس مرة أخرى ، كما في الممارسة العملية ، حاولت إدراج تأخير خمس دورات ، وأنها لم تنجح.

بدلاً من ناقل العنوان الكامل لوحدة FMC ، نستخدم دبوسًا واحدًا فقط A16.

  1. نقوم بتهيئة دبابيس البيانات (D0 - D15) كوظيفة بديلة # 12 ، مثل مجموعة الدفع ، والسرعة القصوى وبدون أي الحمالات.
  2. يتم تكوين الدبابيس XnWAIT و XnWR و XnRD و XA0 و XnCS كدالة بديلة # 12 ، مثل الدفع بالضغط مع رفع إلى علامة الجمع (PULL UP).
  3. نحن نقوم بتكوين XnRST ك GPIO منتظم بدون حامل تعليق (يكون على السبورة نفسها).
  4. XnINTR قابل للتكوين ك GPIO للإدخال مع رفع إلى علامة الجمع.

أنا أيضا ربط الإضاءة الخلفية بنسبة 100 ٪ دون السيطرة عليها عبر PWM. للقيام بذلك ، يتم توصيل رقم 14 على موصل مجموعة الشاشة بـ VDD.

لا أقدم رمز التهيئة للدبابيس ، لأن أستخدم مكتبات التكوين الخاصة بي ، وتم بالفعل مضغ تهيئة GPIO نفسها مائة مرة على لوحة الوصل وعلى مصادر أخرى.

مكتبة التهيئة هنا .

إعدادات FMC


هناك ثلاثة بنوك لكل بنك مسؤولة عن إنشاء بنوك وحدة FMC (NOR Flash / PSRAM / SRAM / ROM / LDC 1). هذه هي FMC_BCRx و FMC_BTRx و FMC_BWTRx. في تعريفات STM32F429 MK ، يتم دمج سجلات FMC_BCRx و FMC_BTRx في صفيف واحد مشترك يسمى FMC_BTCR مع ثمانية عناصر ، حيث يكون العنصر صفر FMC_BCR1 ، والعنصر الأول هو FMC_BTR1 ، والعنصر الثاني هو FMC_BCR2 ، والعنصر الثاني هو FMC_BCR2. يتم دمج FMC_BWTRx في صفيف FMC_BWTR مع سبعة عناصر ، على الرغم من أنه يجب أن يكون هناك أربعة. لا تسألني لماذا ...

يحتوي FMC_BCRx على الإعدادات الأساسية ، ويحتوي FMC_BTRx على توقيتات عامة ، ويحتوي FMC_BWTRx على توقيتات منفصلة للقراءة ، إذا كان الجهاز يتطلب ذلك.

مخطط التوقيت وتوقيت تفاعل STM32F429 و RA8876.



لسهولة التكوين ، سنقوم بإدخال توقيتات بروتوكول 8080 في الثوابت. اخترت توقيت نفسي تجريبيا ، مما يقلل قليلا من القيمة ، لأنه يشبه جدول التوقيت مع ورقة البيانات حصان كروي في فراغ.

unsigned long ADDSET = 0; unsigned long ADDHLD = 1; unsigned long DATAST = 5; unsigned long BUSTURN = 0; unsigned long CLKDIV = 1; unsigned long DATLAT = 0; unsigned long ACCMOD = 0; RCC->AHB3ENR |= RCC_AHB3ENR_FMCEN; //  FMC FMC_Bank1->BTCR[0] = 0; //    FMC_Bank1->BTCR[0] |= FMC_BCR1_MWID_0; //    16  FMC_Bank1->BTCR[0] |= FMC_BCR1_WREN; //    FMC_Bank1->BTCR[0] |= FMC_BCR1_WAITEN; //   XnWAIT FMC_Bank1->BTCR[0] |= FMC_BCR1_ASYNCWAIT; // XnWAIT    FMC_Bank1->BTCR[0] |= FMC_BCR1_WAITCFG; //  XnWAIT FMC_Bank1->BTCR[1] = 0; //    FMC_Bank1->BTCR[1] |= (ADDSET << 0) | (ADDHLD << 4) | (DATAST << 8) | (BUSTURN << 16) | (CLKDIV << 20) | (DATLAT << 24) | (ACCMOD << 28); //   FMC_Bank1->BTCR[0] |= 1; //    

قيمة التسجيل FMC_BTCRx بعد إعادة التعيين هي 0x0FFF FFFF ، أي يتم تعيين الحد الأقصى توقيت. إذا كان لديك عرض أو ذاكرة جديدة ، ما عليك سوى خفض التوقيت ومحاولة التشغيل.

عرض التهيئة


يأتي العمل مع الشاشة إلى القراءة أو الكتابة إلى مناطق معينة من الذاكرة. FMC يعتني بباقي العمل. لتبسيط العمل ، نحدد تعريفين:

 #define LCD_DATA 0x60020000 #define LCD_REG 0x60000000 

والآن نصف الوظائف ذات المستوى المنخفض:

 void LCD_CmdWrite (unsigned char cmd) { *(unsigned short *)(LCD_REG) = cmd; }; void LCD_DataWrite (unsigned short data) { *(unsigned short *)(LCD_DATA)= data; }; unsigned char LCD_StatusRead(void) { unsigned short data = *(unsigned short *)(LCD_REG); return data; }; unsigned char LCD_DataRead(void) { unsigned short data = * (unsigned short *)(LCD_DATA); return (unsigned char)data; }; void LCD_RegisterWrite(unsigned char cmd, unsigned char data) { *(unsigned short *)(LCD_REG) = cmd; *(unsigned short *)(LCD_DATA) = data; }; unsigned char LCD_RegisterRead (unsigned char cmd) { volatile unsigned char data = 0; LCD_CmdWrite (cmd); data = LCD_DataRead (); return data; }; 

علاوة على ذلك ، وظيفة تهيئة العرض نفسها. الرمز مأخوذ من مزود الشاشة ويعاد تصميمه ليلائم احتياجاتك. تحتل الوظائف الفرعية مقدارًا كبيرًا ولن أعطيها في هذه المقالة.

رابط إلى السائق على جيثب

 void RA8876_Init(void) { RA8876_PLL_Init (); //   RA8876  120  RA8876_SDRAM_Init (); //  SDRAM  166  TFT_24bit (); //    24   ??? Host_Bus_16bit (); //   16  RGB_16b_16bpp (); //   16  MemWrite_Left_Right_Top_Down (); //       . Graphic_Mode (); //    Memory_Select_SDRAM (); //   SDRAM /*  RGB     RA8876 */ HSCAN_L_to_R (); VSCAN_T_to_B (); PDATA_Set_RGB (); PCLK_Falling (); DE_High_Active (); HSYNC_High_Active (); VSYNC_High_Active (); LCD_HorizontalWidth_VerticalHeight (1024, 600); LCD_Horizontal_Non_Display (160); LCD_HSYNC_Start_Position (160); LCD_HSYNC_Pulse_Width (70); LCD_Vertical_Non_Display (23); LCD_VSYNC_Start_Position (12); LCD_VSYNC_Pulse_Width (10); //   Frame_Buffer_Start_Address (PAGE0_START_ADDR); Frame_Buffer_Width (1024); Frame_Buffer_Start_XY (0, 0); Frame_Buffer_Color_Mode_16bpp (); //   Canvas_Window_Start_Address (PAGE0_START_ADDR); Canvas_Window_Width (1024); Canvas_Window_Start_XY (0, 0); Canvas_Window_WH (1024, 600); Canvas_Memory_XY_Mode (); Canvas_Window_Color_Mode_16bpp (); } 

حول framebuffer ومنطقة نشطة أكثر من ذلك بقليل. بالنسبة إلى هذين الإعدادين ، نحدد التعريفات التالية:

 #define PAGE0_START_ADDR 0 #define PAGE1_START_ADDR (1024 * 600 * 2 * 1) #define PAGE2_START_ADDR (1024 * 600 * 2 * 2) #define PAGE3_START_ADDR (1024 * 600 * 2 * 3) #define PAGE4_START_ADDR (1024 * 600 * 2 * 4) #define PAGE5_START_ADDR (1024 * 600 * 2 * 5) #define PAGE6_START_ADDR (1024 * 600 * 2 * 6) #define PAGE7_START_ADDR (1024 * 600 * 2 * 7) #define PAGE8_START_ADDR (1024 * 600 * 2 * 8) #define PAGE9_START_ADDR (1024 * 600 * 2 * 9) #define PAGE10_START_ADDR (1024 * 600 * 2 * 10) #define PAGE11_START_ADDR (1024 * 600 * 2 * 11) #define PAGE12_START_ADDR (1024 * 600 * 2 * 12) 

كل صفحة (PAGEx_START_ADDR) هي عنوان البداية في SDRAM. في 16 ميجابايت من الذاكرة ، يمكننا وضع 13 طبقة كاملة بحجم 1228800 بايت (1024 * 600 * 2).
تقوم وظيفة Frame_Buffer_Start_Address بتعيين منطقة الذاكرة الأولية لـ framebuffer (ما يتم عرضه حاليًا).

تعيّن الدالة Canvas_Window_Start_Address منطقة الذاكرة الأولية للوحة القماشية. علاوة على ذلك ، قد يكون حجم اللوحة القماشية أكبر من الإطار المعدني ، بحيث يمكنك تمرير الصورة على الشاشة. على سبيل المثال ، بالنسبة إلى لعبة النظام الأساسي ، يمكنك إنشاء لوحة قماش طويلة بقياس 13312 × 600 بكسل ومن ثم التمرير أفقياً عن طريق تحريك أداة تثبيت الإطار على الجانب الآخر.

إذا قارنت إخراج الرسومات مع LTDM من STM32 ، فكل شيء ليس وردياً هنا. في الوقت نفسه ، يمكن لبرنامج التشغيل نفسه عرض طبقة واحدة (عازلة) نهائية واحدة ، و LTDC في آن واحد ، مع مزجها ، دون الحاجة إلى مشاركتك في هذه العملية.

رسم بدائية


شفرة من مزود شاشة مع ميزات مسبقة الصنع:

 void Start_Line (void); void Start_Triangle (void); void Start_Triangle_Fill (void); void Line_Start_XY (unsigned short WX, unsigned short HY); void Line_End_XY (unsigned short WX, unsigned short HY); void Triangle_Point1_XY (unsigned short WX, unsigned short HY); void Triangle_Point2_XY (unsigned short WX, unsigned short HY); void Triangle_Point3_XY (unsigned short WX, unsigned short HY); void Square_Start_XY (unsigned short WX, unsigned short HY); void Square_End_XY (unsigned short WX, unsigned short HY); void Start_Circle_or_Ellipse (void); void Start_Circle_or_Ellipse_Fill (void); void Start_Left_Down_Curve (void); void Start_Left_Up_Curve (void); void Start_Right_Up_Curve (void); void Start_Right_Down_Curve (void); void Start_Left_Down_Curve_Fill (void); void Start_Left_Up_Curve_Fill (void); void Start_Right_Up_Curve_Fill (void); void Start_Right_Down_Curve_Fill (void); void Start_Square (void); void Start_Square_Fill (void); void Start_Circle_Square (void); void Start_Circle_Square_Fill (void); void Circle_Center_XY (unsigned short WX, unsigned short HY); void Ellipse_Center_XY (unsigned short WX, unsigned short HY); void Circle_Radius_R (unsigned short WX); void Ellipse_Radius_RxRy (unsigned short WX, unsigned short HY); void Circle_Square_Radius_RxRy (unsigned short WX, unsigned short HY); 

على سبيل المثال ، لرسم مثلث معبأ ، قمنا بتعيين ثلاث نقاط: Triangle_Point1_XY و Triangle_Point2_XY و Triangle_Point2_XY وتشغيل وظيفة Start_Triangle_Fill.

العمل مع DMA


للراحة ، كتبت وظيفتي مع هيكل كمعلمة مرت:

 struct GFX_BTE_options { unsigned long layer_s0_addr; //     0 unsigned long layer_s1_addr; //     1 unsigned long layer_d_addr; //     unsigned short layer_s0_width; //    0 unsigned short layer_s1_width; //    1 unsigned short layer_d_width; //    unsigned short layer_s0_start_x; //     0 unsigned short layer_s0_start_y; //   Y  0 unsigned short layer_s1_start_x; //   X  1 unsigned short layer_s1_start_y; //   Y  1 unsigned short layer_d_start_x; //   X   unsigned short layer_d_start_y; //   Y   unsigned short window_size_x; //     unsigned short window_size_y; //     unsigned char rop_code; //  ROP unsigned char operation_code; //   DMA };       DMA: void GFX_BTE_operation (struct GFX_BTE_options options) { BTE_S0_Color_16bpp (); BTE_S0_Memory_Start_Address (options.layer_s0_addr); BTE_S0_Image_Width (options.layer_s0_width); BTE_S0_Window_Start_XY (options.layer_s0_start_x, options.layer_s0_start_y); BTE_S1_Color_16bpp (); BTE_S1_Memory_Start_Address (options.layer_s1_addr); BTE_S1_Image_Width (options.layer_s1_width); BTE_S1_Window_Start_XY (options.layer_s1_start_x, options.layer_s1_start_y); BTE_Destination_Color_16bpp (); BTE_Destination_Memory_Start_Address (options.layer_d_addr); BTE_Destination_Image_Width (options.layer_d_width); BTE_Destination_Window_Start_XY (options.layer_d_start_x, options.layer_d_start_y); BTE_Window_Size (options.window_size_x, options.window_size_y); BTE_ROP_Code (options.rop_code); BTE_Operation_Code (options.operation_code); BTE_Enable (); Check_BTE_Busy (); } 

وصف أكواد التشغيل (كود التشغيل):

0000: اكتب إلى الذاكرة باستخدام ROP باستخدام MK.
0001: قراءة الذاكرة دون ROP باستخدام MK.
0010: انسخ كتلة ذاكرة في الاتجاه الأمامي باستخدام ROP.
0011: نسخ كتلة ذاكرة في الاتجاه المعاكس باستخدام ROP.
0100: اكتب إلى الذاكرة (بشفافية) بدون ROP باستخدام MK.
0101: نسخ (نقل) كتلة ذاكرة (مع الشفافية) في الاتجاه الأمامي دون ROP.
0110: املأ بنمط باستخدام ROP.
0111: املأ القالب باستخدام chromakey.
1000: تمديد اللون
1001: اللون المحسن مع الشفافية
1010: تحريك كتلة ذاكرة للأمام مع مزج ألفا
1011: اكتب للذاكرة باستخدام مزج ألفا باستخدام MK.
1100: تعبئة مساحة الذاكرة بلون خالص.
1101: محفوظة
1110: محفوظة
1111: محفوظة

وصف الرموز النقطية (ROP CODE):

0000b: 0 (أسود)
0001b: ~ S0 ・ ~ S1 أو ~ (S0 + S1)
0010b: ~ S0 ・ S1
0011b: ~ S0
0100b: S0 ・ ~ S1
0101b: ~ S1
0110b: S0 ^ S1
0111b: ~ S0 + ~ S1 أو ~ (S0 ・ S1)
1000b: S0 ・ S1
1001b: ~ (S0 ^ S1)
1010b: S1
1011b: ~ S0 + S1
1100b: S0
1101b: S0 + ~ S1
1110b: S0 + S1
1111 ب: 1 (أبيض)

S0 هي الطبقة الصفرية ، S1 هي الطبقة الأولى. يحدث التفاعل بينهما باستخدام العمليات الحسابية والبت.

إخراج الخط المضمنة


 void GFX_Show_String_TMODE (short x, short y, char *ptr, unsigned short charColor, unsigned short bkColor) { Foreground_color_65k (charColor); Background_color_65k (bkColor); CGROM_Select_Internal_CGROM (); Font_Select_12x24_24x24 (); Text_Mode (); Goto_Text_XY (x, y); LCD_CmdWrite (0x04); while (*ptr != '\0') { LCD_DataWrite (*ptr); Check_Mem_WR_FIFO_not_Full (); ++ptr; } Check_2D_Busy (); Graphic_Mode (); //back to graphic mode } 

يمكن العثور على النسخة الكاملة من برنامج التشغيل على جيثب على الرابط

شكرا لكم جميعا على القراءة!

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


All Articles