[TH] How to build MicroPython for esp32-C3.

บทความนี้กล่าวถึงการคอมไพล์ (build) และใช้งาน MicroPython สำหรับไมโครคอนโทรลเลอร์ esp32-C3 ที่ได้เคยแนะนำไปแล้ว โดยขั้นตอนยังเหมือนกับการคอมไพล์สำหรับ esp32-s2 นอกจากนี้ทีมงานได้ดำเนินการแก้ไขปัญหาเรื่องของ RS232-to-USB จากที่บอร์ดใช้ CH340 ไปต่อขาภายนอกโดยใช้ CP2102 แทน และต่อโมดูลแสดงผลด้วย OLED ดังภาพที่ 1

ภาพที่ 1 บอร์ด ESP32-C3 ที่ต่อเติมโมดูล OLED และขาสำหรับเชื่อมต่อภายนอก

ขั้นตอน

ก่อนจะคอมไพล์ผู้อ่านจะต้องมีชุด ESP-IDF ก่อนซึ่งสามารถอ่านได้จากบทความก่อนหน้านี้ หรือจากตัวอย่างการคอมไพล์สำหรับ ESP32 ผ่านทาง WSL เมื่อมีคอมไพล์เลอร์ติดตั้งในระบบเป็นที่เรียบร้อยก็มาสู่ ขั้นตอนการคอมไพล์ MicroPython เป็นดังนี้

ดาวน์โหลด

ให้ดาวน์โหลดไฟล์ต้นฉบับของ MicroPython จาก github ด้วยคำสั่งต่อไปนี้

git clone --recurse-submodules https://github.com/micropython/micropython.git

ตัวอย่างผลลัพธ์ของการทำงานเป็นดังภาพที่ 2

git clone --recurse-submodules https://github.com/micropython/micropython.git
ภาพที่ 2 ตัวอย่างผลลัพธ์จากการสั่ง git clone

เมื่อดาวน์โหลดเป็นที่เรียบร้อยให้ใช้คำสั่งย้ายเข้าไปในโฟลเดอร์ของ micropython ดังนี้

cd ~/micropython

คอมไพล์ mpy-cross

ตัวคอมไพล์ภาษาไพธอนของ MicroPython หรือ mpy-cross ให้เป็นไบต์โค้ดที่มีนามสกุลเป็น .mpy ซึ่งมีประโยชน์ในแง่ของการทำให้โค้ดนั้นมีขนาดเล็กลงสะดวกต่อการนำไปใช้เนื่องจากประหยัดพื้นที่ของรอม/แรม และไม่ต้องประมวลผลขณะที่เรียกทำงาน นอกจากนี้ ในการคอมไพล์ MicroPython เองก็ต้องใช้ตัว mpy-cross ด้วยเช่นกัน ดังนั้น สิ่งที่ต้องทำในขัเนตอนที่ 2 คือ คอมไพล์ mpy-cross เพื่อเป็นเครื่องมือสำหรับคอมไพล์ MicroPython ต่ออีกชั้นหนึ่ง โดยเข้าไปที่ mpy-xxx หลังจากนั้นสั่ง make ดังนี้

cd mpy-cross

make clean

make

เมื่อคอมไพล์เสร็จจะพบไฟล์ชื่อ mpy-cross

คอมไพล์ submodules ของ esp32

เมื่อมี mpy-cross แล้ว ขั้นตอนต่อไปคือสร้างไลบรารีที่จะถูกเรียกใช้ด้วย esp32-s2 โดยเข้าไปที่ ports ของ ESP32 ดังนี้

cd ~/micropython/ports/esp32

หลังจากนั้นสั่งคอมไพล์ด้วยคำสั่งดังต่อไปนี้

make  clean
make  submodules

ปรับแต่ง Partition

เนื่องจากบอร์ดที่ทางเรามีนั้นมี Flash เพียง 2MB จึงต้องปรับแก้รายละเอียดของพาร์ทิชันของรอมในไฟล์ partitions.csv ให้เป็นดังนี้

nvs,        data, nvs,     0x9000,   0x6000,
phy_init,   data, phy,     0xf000,   0x1000,
factory,    app,  factory, 0x10000,  0x160000,
vfs,        data, fat,     0x170000, 0x50000,

คอมไพล์ MicroPython

คำสั่งสำหรับคอมไพล์ MicroPython เพื่อใช้กับ ESP32-C3คือ กำหนดให้บอร์ดที่ใช้งานเป็น GENNERIC_C3 ดังนี้

make BOARD=GENERIC_C3

เมื่อการคอมไพล์เสร็จสิ้นโดยไม่เกิดข้อผิดพลาดเกี่ยวกับ ESP-IDF หรือลืม mpy-cross จะได้โฟลเดอร์ชื่อ build-GENERIC_C3

อัพโหลด

เมื่อคอมไพล์เรียบร้อย ขั้นตอนต่อไปคืออัพโหลดเข้าบอร์ด ซึ่งต้องตรวจสอบการตั้งค่าของสวิตช์ให้เป็นดังภาพที่ 3 หลังจากนั้นสั่งงานดังนี้

~/.espressif/python_env/idf4.4_py3.8_env/bin/python ../../../esp-idf/components/esptool_py/esptool/esptool.py -p (PORT) -b 460800 --before default_reset --after hard_reset --chip esp32c3  write_flash --flash_mode dio --flash_size detect --flash_freq 80m 0x0 build-GENERIC_C3/bootloader/bootloader.bin 0x8000 build-GENERIC_C3/partition_table/partition-table.bin 0x10000 build-GENERIC_C3/micropython.bin

โดยให้เปลี่ยน (PORT) เป็นไดเร็กทีรีของพอร์ต เช่น /dev/ttyUSB0 เป็นต้น

ทดสอบการทำงาน

ตัวอย่างโปรแกรมอ่านข้อมูลของบอร์ด เขียนได้ดังนี้

##################################################################################
# coreInfo
##################################################################################
import gc
import os
import sys
import time
import machine as mc

##################################################################################
# system setting
##################################################################################
gc.enable()
gc.collect()

mc.freq(160000000)

##################################################################################
# system setting
##################################################################################
def show_hw_info():
    uname = os.uname()
    mem_total = gc.mem_alloc()+gc.mem_free()
    free_percent = "("+str((gc.mem_free())/mem_total*100.0)+"%)"
    alloc_percent = "("+str((gc.mem_alloc())/mem_total*100.0)+"%)"
    stat = os.statvfs('/flash')
    block_size = stat[0]
    total_blocks = stat[2]
    free_blocks  = stat[3]
    rom_total = (total_blocks * block_size)/1024
    rom_free = (free_blocks * block_size)/1024
    rom_usage = (rom_total-rom_free)
    rfree_percent = "("+str(rom_free/rom_total*100.0)+"%)"
    rusage_percent = "("+str(rom_usage/rom_total*100.0)+"%)"
    print("ID ............:",mc.unique_id())
    print("Platform ......:",sys.platform)
    print("Version .......:",sys.version)
    print("Memory")
    print("   total ......:",mem_total/1024,"KB")
    print("   usage ......:",gc.mem_alloc()/1024,"KB",alloc_percent)
    print("   free .......:",gc.mem_free()/1024,"KB",free_percent)
    print("ROM")
    print("   total ......:", rom_total,"KB" )
    print("   usage ......:", rom_usage,"KB",rfree_percent )
    print("   Free .......:", rom_free,"KB",rusage_percent )
    print("system name ...:",uname.sysname)
    print("node name .....:",uname.nodename)
    print("release .......:",uname.release)
    print("version .......:",uname.version)
    print("machine .......:",uname.machine)
    print("Frequency .....:",mc.freq())
    try:
        import ulab
        print("ulab ..........:",ulab.__version__)
    except:
        print("ulab ..........: None")
    
##################################################################################
# main program
##################################################################################
try:
    show_hw_info()
except KeyboardInterrupt:
    pass
print("end of program")


ตัวอย่างผลลัพธ์ของการทำงานเป็นดังภาพที่ 3

ภาพที่ 3 ตัวอย่างผลลัพธ์ของโปรแกรม

ตัวอย่างการหาจำนวนเฉพาะจากตัวเลข 2 ถึง 2000 จากโค้ดต่อไปนี้ได้ผลลัพธ์ดังภาพที่ 4

import gc
import time as tm
import machine as mc

gc.enable()
gc.collect()

mc.freq(160000000)

def is_prime(x):
    i = 2
    while (i < x):
        if x%i == 0:
            return False
        i = i+1
    if (i == x):
        return True
    return False

def test_prime_number(maxN):
    counter = 0
    t0 = tm.ticks_ms()
    for n in range(2, maxN):
        if is_prime(n):
            counter+=1
    t1 = tm.ticks_ms()
    print("Found {} in {} msecs.".format(counter,abs(t1-t0)))
    
test_prime_number(2000)
ภาพที่ 4 ผลลัพธ์จากการหาจำนวนเฉพาะของ ESP32-C3

สรุป

จากบทความนี้จะพบว่าการสร้าง MicroPython เพื่อใช้กับไมโครคอนโทรลเลอร์ ESP32-C3 นั้นมีขั้นตอนเหมือนกับ ESP32 แต่จุดที่แตกต่างคือ ต้องตรวจสอบขนาดหน่วยความจำแฟลชเนื่องจากมีผลต่อการจัดวางพาร์ทิชัน และต้องตรวจสอบความเข้ากันได้ของโมดูล RS232-USB ว่าระบบปฏิบัติการที่ใช้งานนั้นรองรับหรือไม่ ถ้าไม่รองรับ ผู้อ่านสามารถนำโมดูล RS232-to-USB ที่ระบบปฏิบัติการรองรับต่อเข้ากับ GND, 5V หรือ 3V3, RX และ TX เพื่อใช้งานได้

ส่วนหลักภาษาเขียนโปรแกรมยังคงเป็นภาษาไพธอนเหมือนกับ ESP32 ที่ทางเราได้อัพบทความมาตลอด และ สุดท้ายขอให้สนุกกับการเขียนโปรแกรมครับ

ท่านใดต้องการพูดคุยสามารถคอมเมนท์ได้เลยครับ

แหล่งอ้างอิง

  1. MicroPython

(C) 2020-2021, โดย อ.ดนัย เจษฎาฐิติกุล/อ.จารุต บุศราทิจ
ปรับปรุงเมื่อ 2021-10-24, 2021-12-30