حل مشكلة الWiFi للوحة Arduino Giga R1 WiFi

مؤخرًا مع بداية شهر 3 أطلقت شركة Arduino لوحة Arduino Giga R1 حيث أنها تأتي بإمكانيات عالية وتتضمن معها وحدة WiFi مما يجعلها مناسبة لتطبيقات إنترنت الأشياء، ولكن واجهتني إشكالية تحول بيني وبين تفعيل ميزة الWiFi، سنتحدث عنها لاحقًا.

بشكل مختصر لوحة Arduino Giga R1 WiFi، عبارة عن لوحة تطوير مبنية على متحكم دقيق يدعى STM32H747XIH6 ويمتاز هذا المتحكم بسرعة عالية بالإضافة لكونه مبني على معمارية Arm Cortex M7 فيجعله مناسبٌا لمختلف تطبيقات الهندسية المعقدة.

مميزات لوحة Arduino Giga R1 WiFi

  • مبني على المتحكم STM32H747XIH6
    • يحتوى على تعليمات معالجة الإشارات الرقمية
    • يتوفر على وحدة MPU
  • وحدة اتصال الخاصة بالوايفاي والبلوتوث Murata 1DX
  • الذاكرة
    • STM32H747XI
      • 2 ميجا بايت من ذاكرة الفلاش.
      • 1 ميجا بايت من ذاكرة الوصول العشوائي (RAM).
    • AT25SF128A-MHB-T ذاكرة فلاش خارجية
      • 16 ميجا بايت ذاكرة فلاش من نوع NOR.
      • بواجهة تخاطب QUAD SPI.
    • AS4C4M16SA
      • 8 ميجابايت من ذاكرة وصول عشوائي من نوع ديناميكي.
  • وحدات الإدخال و الإخراج
    • 76 مدخل ومخرج رقمي.
    • 12 مدخل تماثلي.
    • 12 منفذ بعرض نبضي متغير.
    • 2 مخارج تماثلية.
    • دعم لبروتوكول USB.
    • جهد التخاطب المنطقي 3.3 فولت.
  • واجهات التخاطب (Communication Protocols)
    • 4x UART
    • 3x I2C
    • 2x SPI
    • Can bus يتطلب وجود مستقبل ومرسل خارجي.
  • USB
    • USB HOST
    • USB Peripheral Type-C
  • منافذ جاهزة للاستخدام بشكل مباشر
    • منفذ الكاميرا.
    • منفذ الشاشة.
    • منفذ صوتيات.
  • التغذية
    • جهد عمل الدائرة 3.3 فولت
    • الجهد المسموح لتغذية اللوحة من 6 إلى 24 فولت.

هذه مميزات اللوحة بشكل مختصر، والآن سنتجه للإشكالية التي واجهتني خلال عملي واختبارها.

تتمثل الإشكالية بشكل محدد حول عدم إمكانية قراءة من ذاكرة الفلاش الخارجية بشكل صحيح باستخدام حزمة البرمجية التي تأتي بشكل رسمي من شركة الArduino، وقد بدأت المشكلة مع عدم إمكانية تفعيل وحدة الWiFi، حيث كان يظهر خطأ بعدم وجود الملف التشغيلي للWiFi (في عالم العتاد أو الهاردوير يطلق عليه بالفيرموير Firmware) فقررت استخدام الكود المرفق مع الحزمة وللأسف حال دون ذلك.

فكان البرنامج يقف عند هذه النقطة دون تقدم مع وجود إضاءة تحذيرية من اللوحة تبلغ عن وجود خطأ.

No filesystem containing the WiFi firmware was found.
Usually that means that the WiFi firmware has not been installed yet or was overwritten with another firmware.

Formatting the filsystem to install the firmware and certificates...

Error Format Flash: -3101
Flashing /wlan/4343WA1.BIN file
Flashed 0%

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

Available partition schemes:

Partition scheme 1
Partition 1: WiFi firmware and certificates 1MB
Partition 2: OTA and user data 13MB

Partition scheme 2
Partition 1: WiFi firmware and certificates 1MB
Partition 2: OTA 5MB
Partition 3: User data 8MB

Do you want to use partition scheme 1? Y/[n]
If No, partition scheme 2 will be used.

WARNING! Running the sketch all the content of the QSPI flash will be erased.
Do you want to proceed? Y/[n]
Error formatting WiFi partition

فهنا تيقنت جيدًا ربما يكون هناك خلل على صعيد البرمجي أو العتاد، فقررت أن اعمل على بحث عن أصل الإشكالية و وصلت لنتيجة أنه هناك خلل مع ذاكرة الفلاش الخارجية حيث أنه لا تستطيع قراءة البيانات على وضع (Fast Quad Mode I/O) (مستقبلًا سأكتب مقالة مفصلة عن ماهية الQSPI) بشكلها الصحيح، مما دفعني لتطوير مكتبة تحل الإشكالية لحين اصلاحها من طرف شركة الArduino.

حيث أنه تعمل المكتبة على تحميل الملف التشغيلي لأول مرة ومن ثم استخدامها كبديل عن المكتبة الافتراضية.

رابط المكتبة: https://github.com/ahmedalkabir/GigaWiFiSolver

نقوم بتحميل المكتبة من الرابط المرفق مسبقًا، واتباع الخطوات الآتية:

ننقل مجلد المكتبة إلى مسار التالي Document/

نقوم برفع البرنامج كما موضح في الصور.

ومن ثم سيقوم البرنامج بتحميل البرنامج التشغيلي لوحدة الWiFi على ذاكرة الفلاش الخارجية.

بعد الانتهاء من البرنامج لنقوم باختبارالبرنامج WiFi المرفق مع المكتبة.

وكما يبدو واضحًا، وحدة الWiFi تعمل بشكل جيد بدون أي مشكلة، يجدر الملاحظة أنه لكي تعمل وحدة الWiFi بشكل ممتاز يجدر إضافة مكتبة GigaWiFiSolver في بداية السطر حيث ستعمل كبديل عن المكتبة الإفتراضية التي تأتي مع الحزمة.

وهكذا قمت بحل الإشكالية التي واجهتني و قريبًا ستكون هناك سلسلة مقالات حول لوحة الArduino Giga R1 والمشاريع التي سأقوم بها باستخدام هذه اللوحة.

المؤشرات Pointers في لغة الC، جزء الأول

المقدمة

من فترة كنت نشتغل على مشروع وقعدت بشكل مباشر نتعامل مع المؤشرات Pointers، في الغالب لو كنت بتبدا مسيرتك مع لغة الC المؤشرات راح تكون جنبك طالما تتعامل مع لغة الC دائمًا، عيب المؤشرات أنها صعبة الإستيعاب من البداية بحيث أنه المفهوم يعتبر جديد وغريب نسبيًا بحيث أن مع بداية التعلم الشخص لهذه لغة من بداية أو لأول مرة في عالم البرمجة بيكون المفهوم غريب بعض الشئ، على العموم هو نحاول نطرح سلسلة مقالات حول لغة C من فترة لفترة حيث أنه بنبدأ بالمؤاشرت حاليًا وجزء الأول راح يتعلق كفكرة من الأول وطرح المقالات بيكون بلغة العامية بعض الشئ لو في أي تعليق بخصوص هذا الموضوع أترك تعليق في الأسفل

لنبدأ بالمؤشرات، المؤشرات في لغة الC تعتبر جزء لا يتجزأ عنها وبالأخص أنها راح تعطيك مرونة وقوة في كتابة برنامجك، وبجانب هذا تعتبر شق مهم في إدارة الذاكرة بالنسبة للغة C، إتقانك للمؤشرات وفهمك ليهم بشكل جيد، راح يخليك تكتب برامج بلغة C بشكل كويس.

أذن ماهي المؤشرات أو ماهو المؤشر بحد ذاته، الفكرة من مؤشر هي إنك تأخذ عنوان المتغير لاحظ قلت أنه ياخذ عنوان المتغير وليس قيمة المتغير بحد ذاته، يعنى لما تحاول تسند قيمة لمتغير بطريقة هذه

int i = 10;

وكما تلاحظ محتوى المتغير راح يكون رقم 10، توا المتغير بحد ذاته في لغة الC وربما كل لغات البرمجية الأخرى، تتكون من عنوان في الذاكرة وقيمة ليحملها هذا العنوان، وتذكر أنه أسم المتغير الi أو غيره مايعنى شئ للكومبيوتر لأن يفهم بالعناوين والقيم، أسم المتغيرعادة يرمز له symbol ونفس الأمر مع اسم الدوال والstruct، الsymbol ماهي إلا مجرد تسهيل لنا نحن كمبرمجين للعمل على حل المشاكل.

بجانب أن قلت المتغير يتكون من عنوان وقيمة، نفس الأمر ينطبق على متغير من نوع مؤشر pointer، غير أن نوع القيمة ليست مثل نوع المتغير الإعتيادي يعنى مثل integer أو float أو user-defined structure، قيمته تكمن في عنوان المتغير يعنى المتغير من نوع مؤشر هو متغير يخزن قيم عناوين المتغير بالطريقة هذه

int i = 10;
int *pInt = &i;

لاحظ في المثال السابق أن علامة * دلالة على أنه المتغير من نوع مؤشر pointer ولأي نوع يأشر، يأشر لنوع integer، يعنى (pInt is pointer to int ) ، طبعًا الشئ هذا مهم ويأخذ في الحسبان بشكل كبير وراح أتطرق لسبب ليش نوع المتغير مهم في عمليات المؤشر pointer arithmetic.

توا السؤال كيف يأخذ عنوان المتغير ؟؟ تتم العملية عن طريق مايسمى بعملية referencing وبإستعمال عملية &، حيث أن ال& تعطيك عنوان المتغير في الذاكرة ويسندها للمؤشر، (يجدر الذكر أنه لا يجب الخلط بين & كعملية AND و ك& كعملية referencing حيث تستعمل الأخيرة في عملية إسناد عنوان المتغير للمؤشر أو لدالة كتمريرها كعنوان reference).

توا سؤال أخر يطرح، هل عملية التعامل مع المتغيرات من النوع مؤشر pointer مثل المتغير الإعتيادي ؟؟ الإجابة إيه ولا، كيف يعنى ؟؟

واحد من تطبيقات المؤشر pointer وهي أكثرها شيوعًا أنه يتم تمرير المتغيرات كعنوان reference، أو بالأحرى تتم عملية تبادل البيانات بسرعة بدون مايدير copying يعنى نسخ قيم المتغير، ليتضح أنه في كفاءة في التعامل مع المتغيرات والقيم الكبيرة لي تستهلك وقت في النسخ حيث أن يتم إستعمال المؤشرات بأخذ عنوان المتغير بدل مايأخذ القيمة بشكل كامل وينسخها كلها.

التعامل مع المؤشرات

التعامل مع المؤشرات عادة تنقسم لنوعين، تعامل معه كمتغير عادي أو كمؤشر، كيف تتعامل معاه كمتغير عادي؟؟ خلي نجي نشوفوا للمثال هذا

// usual variable 
int i = 10;
// i  لا حظ أن تم أخذ عنوان المتغير 
int *iPtr = &i;
// لإستعماله كمتغير عادي أو بالأحرى تعامل معاه كأنه متغير تحتاج إلى عملية تسمى 
// Dereferencing
// حيث تتيح لك أخذ قيمة المتغير أو تغيره 
// i هنا تم نسخ قيمة المتغير  السابق  
// y إلى 
int y = *iPtr;

في الكود السابق يوضح أني خزنت قيمة لكان يأشرلها المتغير iPtr للمتغير i لي y، ركز هنا أني قلت يأشرلها مش يأخذ قيمة المتغير الiPtr، المتغير iPtr بحد ذاته عنوان يعنى يأشر لعنوان معين زي عنوان الi، والi قيمتها تساوي 10، بمعنى أن الy نسخت بشكل غير مباشر قيمة الi عن طريق المؤشر iPtr بإستعمال عملية Dereferencing يعنى بإضافة * قبل المؤشر iPtr في عملية الإسناد القيمة، ركز أني قلت الإسناد، يعنى باهي لو درت هكي

int y = iPtr;

ليصير هنى بالضبط أنك تنسخ في عنوان المتغير i، هل تقدر تتلاعب بقيمة المؤشر iPtr ؟؟؟ نعم، تقدر تغير قيمة المؤشر يأما بقيمته بإستعمال Dereferencing

int i = 10;
int iPtr = &i;
*iPtr = 10*10;
// قيمة المتغير راح تتغير إلى 100 لأن لصار مثل هذه
i = 10*10;

كيف ممكن تغيرت قيمة الi ؟؟ تتفكر لما قتلك أن المتغير من نوع مؤشر يأخذ عنوان المتغير يعنى بالضبط يأِشرله ليه يعنى زي عملية ربط بينه وبين المتغير i مثل ماتقول أي تغير تديره للمتغير iPtr ينطبق على i لأن iPtr مخزن فيه عنوان المتغير i في نفس الوقت أيضًا المتغير iPtr عنده عنوان خاص بيه مثل ماموضح في الصورة

أو يمكنك تتلاعب بقيمة العنوان وتغير عنوان المؤشر لمكان أخر عن طريق يأما الإسناد أو increamting.

شن الفائدة المكتسبة من تعامل مع المتغيرة والإضافة لنستفيد منها أو يضيف حاجات جديدة لخبرتي ؟؟

الفائدة أن لما بتتعامل مع الدوال وتمرر القيم بين الدوال ممكن حي تمرر قيم من نوع structure ولهو عبارة نوع من البيانات يعرفها المتسخدم وتكون فيها أكثر من نوع وغالبًا يكون حجم الstructure كبير ولما تمرر structure معين لدالة حي يكون الأمر مستنزف للبرنامج ويأخذ وقت لنسخ على خاطر أنك بتقرأ قيم ؟؟!! لهذا المؤاشرات تعتبر حل مناسب للمشاكل هذه فقط مرر عنوان structure ودير عملية dereferencing وأقرا القيم بشكل أكفا، يعنى مرر المتغيرات كعنوان بدل كقيم ويعتبر من الgood practice في لغة الC، مع إعتبار هل أنك تحتاج تغير قيمة المتغير أو لا ،ولتفادي هذه المشكلة من المبرمج يتم إضافة const لمنع من أي تغير بشكل غير متوقع

int readFoo(const UserStruct *p);

كيفية تمرير المتغيرات للدوال وغيرها من المواضيع التي طرحها ،ستكون في المقالة القادمة أرجو أن تكون المقالة مفيدة ولو عندك تعليق خليه 😁