วิธีติดตั้ง CircuitPython ลงบน Board SAMD21 Mini
บอร์ด SAMD21 มีขนาดเล็กกระทัดรัด ราคาค่อนข้างถูกประมาณไม่ถึง 10 US$ ดู Spec SAMD21 เทียบกับ UNO R3 ได้ดังนี้
การลง CircuitPython ใน บอร์ด SAMD21มีขั้นตอน 3 ขั้นตอนดังนี้
1.ติดตั้ง Board SAMD21 ใน Arduino IDE ให้มี Option Arduino Zero(Native USB Port) ตอนเลือก Board การติดตั้งใช้ Menu Board Manager เพื่อเพิ่ม
เลือกเพิ่ม “Arduino SAMD Boards (32-bits Arm Cortex-M0+) by Arduino.”
2. ติดตั้ง UFL Bootloader ซึ่งเป็น Arduino Sketch นามสกุล .ino โดย Download UFL bootloader ได้จาก หน้าเวป
https://github.com/adafruit/uf2-samdx1/releases
ไฟล์ที่ Download มาคือ update-bootloader-sparkfun-samd21-mini-v3.10.0.ino เป็นต้น
Flash Board ด้วย .ino ที่ดาวน์โหลดมา
เลือก Board Arduino Zero(Native USB Port)ขณะเริ่ม Flash กดปุ่ม Micro Switch บน Board เร็วๆ 2 ครั้งติดๆ กัน
หลังจาก Flash เสร็จให้ Reboot จะเห็น Virtual Drive ชื่อ SPARKFUN(F:) ตามรูป
3.Download CircuitPython ในรูป uf2 จากหน้าเวป SAMD21 Mini by SparkFun https://circuitpython.org/board/sparkfun_samd21_mini/
ไฟล์ที่ Download มาคือ adafruit-circuitpython-sparkfun_samd21_mini-en_US-5.3.0.uf2 เป็นต้น
COPY File adafruit-circuitpython-sparkfun_samd21_mini-en_US-5.3.0.uf2 วางลงใน Drive SPARKFUN(F:)
หลัง Copy เสร็จ Board จะ Reboot ตัวเองอัตโนมัติ Windows จะพบ Virtual Drive ชื่อ CIRCUITPY (F:)แทน เป็นอันเสร็จสิ้นการลง CircuitPython ลงบน Board SAMD21
การใช้ Thonny IDE
ลองเปิดโปรแกรม Thonny เลือก Interpreter Option ให้ถูกต้อง
กด OK เมื่อ Thonny ติดต่อกับ ฺBoard ได้สำเร็จจะเห็นข้อความ
Adafruit CircuitPython 5.3.0 on 2020–04–29; SparkFun SAMD21 Mini Breakout with samd21g18
สามารถเริ่มใช้งานได้เป็นปรกติ โดยมี Storage Space ประมาณ 43.5kB
ใช้ Mu — A Simple Python Code Editor
จะเห็นว่าเมื่อเสียบสาย USB เข้ากับ SAMD21 บอร์ด แล้ว Mu จะเลือก Mode ให้อัตโนมัติเป็นโหมด CircuitPython (แสดงตรงมุมขวาล่าง) ICON RUN และ REPL ไม่มีขึ้นบนหน้าจอ ถ้าเราต้องการทดสอบการ run ให้ เปลี่ยนชื่อ file เป็น code.py ไฟล์ code.py จะถูก run อัตโนมัติ หากไม่ run อัตโนมัติให้กด Ctrl-D หนึ่งครั้ง สามารถดูผลการ run ได้จากหน้าต่าง Serial
กรณีเรา run โปรแกรมและต้องการหยุด run ให้กด Ctrl-C แล้วตามด้วย Enter
ถ้าจะ Reload ให้กด Ctrl-D
ตัวอย่าง 1.0 scani2c.py
บน Board SAMD21 มีขา SCL และ SDA ให้เชื่อม SCL ของ AHT10 เข้ากับ SCL ของ SAMD21และ SDA ของ AHT10 เข้ากับ SDA ของ SAMD21
import board
import busio
i2c = busio.I2C(board.SCL, board.SDA)while not i2c.try_lock():
pass
print("Scan i2c bus…")
devices = i2c.scan()
if len(devices) == 0:
print("No i2c device !")
else:
print("i2c devices found:", len(devices))
for device in devices:
print("Decimal address: ", device, " | Hexa address: ", hex(device))
i2c.deinit()
ผลการ run
>>> %Run -c $EDITOR_CONTENT
Scan i2c bus…
i2c devices found: 1
Decimal address: 118 | Hexa address: 0x76
ตัวอย่าง 2.0 ShowInfo.py
import sys
print("implementation:", sys.implementation)
print("platform:", sys.platform)
print("path:", sys.path)
print("Python version:", sys.version)
ผลการ run
>>> %Run -c $EDITOR_CONTENT
implementation: (name=’circuitpython’, version=(5, 3, 0))
platform: Atmel SAMD21
path: [‘’, ‘/’, ‘.frozen’, ‘/lib’]
Python version: 3.4.0
ตัวอย่าง 3.0 ReadRXUart.py ใช้เช็คขา RX ที่ต่อกับมอดูลอื่น เช่น มอดูล GPS
การเชื่อมต่อ เสียบ Pin TX จาก GPS เข้าขา RX ของบอร์ด SAMD21
import board
import busio
import digitalio
led = digitalio.DigitalInOut(board.D13)
led.direction = digitalio.Direction.OUTPUT
uart = busio.UART(board.TX, board.RX, baudrate=9600)
while True:
data = uart.read(32) # read up to 32 bytes
# print(data) # this is a bytearray type
if data is not None:
led.value = True
# convert bytearray to string
data_string = ''.join([chr(b) for b in data])
print(data_string, end="")
led.value = False
ผลการ run ถึงอยู่ในร่มภายในอาคาร ก็ต้องอ่านค่าได้หากการต่อสายถูกต้อง เพียงแต่ค่าส่วนใหญ่จะเป็น 0
>>> %Run -c $EDITOR_CONTENT
$GPRMC,,V,,,,,,,,,,N*53
$GPVTG,,,,,,,,,N*30
$GPGGA,,,,,,0,00,99.99,,,,,,*48
$GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30
$GPGSV,1,1,00*79
$GPGLL,,,,,,V,N*64
$GPRMC,,V,,,,,,,,,,N*53
$GPVTG,,,,,,,,,N*30
$GPGGA,,,,,,0,00,99.99,,,,,,*48
$GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30
$GPGSV,1,1,00*79
$GPGLL,,,,,,V,N*64
$GPRMC,,V,,,,,,,,,,N*53
$GPVTG,,,,,,,,,N*30
$GPGGA,,,,,,0,00,99.99,,,,,,*48
$GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30
ตัวอย่าง 4.0 Sensor อุณหภูมิ ความชื้น AHT10
AHT10 เป็น Sensor มีผลการวัดที่ความละเอียดค่อนข้างสูง ดังนี้
- Temperature range: -40°C..+85°C
- Temperature resolution: 0.01°C
- Temperature accuracy: ±0.3°C
- Relative humidity range: 0%..100%
- Relative humidity resolution: 0.024%
- Relative humidity accuracy: ±2%**
- I²C bus speed: 0Hz — 400KHz
- Recomended polling frequency: 8sec — 30sec***
import board
import adafruit_ahtx0
import busio
# Create the sensor object using I2C
i2c = busio.I2C(board.SCL, board.SDA)
sensor = adafruit_ahtx0.AHTx0(i2c)
print("\nTemperature: %0.1f C" % sensor.temperature)
print("Humidity: %0.1f %%" % sensor.relative_humidity)
i2c.deinit()
ผลการ run
Temperature: 30.0 C
Humidity: 47.2 %
ตัวอย่าง 5.0 LoRaWAN ส่งข้อความ Hello
ใช้กับมอดูล Maxiiot DL7612-AS923-TH โดยเชื่อม RX ของ Maxiiot เข้า TX ของ SAMD21 และ TX ของ Maxiiot เข้า RX ของ SAMD21 โปรแกรมทีให้จะส่ง Hello ไปเรื่อยๆ
import time
import board
import busio
import digitalio
def sendATcommand(ATcommand):
print("{0}\r\n".format(ATcommand))
uart = busio.UART(board.TX, board.RX, baudrate=115200, timeout=.1)
uart.write(bytearray(b"{0}\r\n".format(ATcommand)))
rstr = uart.read(270)
if rstr:
rstr = str(rstr, 'utf-8')uart.deinit()
print(rstr)
return (rstr)
sendATcommand("AT+NRB")
time.sleep(20.0)
sendATcommand("AT+INFO")
time.sleep(5.0)
sendATcommand("AT+NCONFIG")
time.sleep(5.0)
cnt = 1
while True:
print("Hello! #{}".format(cnt))
sendATcommand("AT+NMGS=7,01670119026873")
# sendATcommand("AT+NCMGS=5,HELLO\r\n")
cnt = cnt + 1
time.sleep(10.0)
ผลการ run
Hello! #1
AT+NMGS=7,01670119026873+NMGS:0
OKHello! #2
AT+NMGS=7,01670119026873+NMGS:0
OK
หากเกิด Error
Traceback (most recent call last):
File “<stdin>”, line 24, in <module>
File “<stdin>”, line 9, in sendATcommand
ValueError: D0 in use
ให้ Soft Reboot โดยกด Ctrl-D หน้าจอ Shell หนึ่งครั้ง
ตัวอย่าง 6.0 ใช้ Sensor อุณหภูมิ ความชื้น AHT10 ส่งขึ้น LoRaWAN Network Server ด้วยรูปแบบ CayenneLPP
ใช้ LoRaWAN มอดูล Maxiiot DL7612-AS923-TH โดยเชื่อม RX ของ Maxiiot เข้า TX ของ SAMD21 และ TX ของ Maxiiot เข้า RX ของ SAMD21
บน Board SAMD21 มีขา SCL และ SDA ให้เชื่อม SCL ของ AHT10 เข้ากับ SCL ของ SAMD21และ SDA ของ AHT10 เข้ากับ SDA ของ SAMD21
Lib ที่ใช้ ตามรูป และใช้ CayenneLPP.py
import time
import busio
import board
import adafruit_binascii
import adafruit_ahtx0
from cayennelpp import CayenneLPP
rstr = ""
i2c = busio.I2C(board.SCL, board.SDA)
sensor = adafruit_ahtx0.AHTx0(i2c)
def sendATcommand(ATcommand):
print("{0}\r\n".format(ATcommand))
uart = busio.UART(board.TX, board.RX, baudrate=115200, timeout=.1)
uart.write(bytearray(b"{0}\r\n".format(ATcommand)))
rstr = uart.read(250)
if rstr:
rstr = str(rstr, 'utf-8')
uart.deinit()
print(rstr)
return (rstr)
sendATcommand("AT+INFO")
sendATcommand("AT+NCONFIG")
sendATcommand("AT+NRB")
cnt = 1
while rstr != '+CGATT:1':
time.sleep(20.0) # Wait for Join Accept
rstr = sendATcommand('AT+CGATT')
print('Respond String')
print(rstr)
if rstr.startswith('+CGATT:1'):
print('++++OTAA OK+++++')
break
print('Retry OTAA Continue')
while True:
print("********Packet No #{}".format(cnt))
print("********AHT10 values:***********")
temp = sensor.temperature
hum = sensor.relative_humidity
print('temp:', temp, ' Hum:', hum)
time.sleep(2)
c = CayenneLPP()
c.addTemperature(1, float(temp))
c.addRelativeHumidity(2, float(hum))
d = adafruit_binascii.hexlify(c.getBuffer())
print('---------Start Send Status------------')
sendATcommand("AT+NMGS={0},{1}\r\n".format(int(len(d)/2), (str(d)[2:-1])))
print('---------End Send Status--------------')
cnt = cnt + 1
time.sleep(10.0)
ดูค่าที่ Upload ขึ้น ChirpStack ที่ได้เช่น Temp=27.5 Humid=51 โดยทศนิยมจะถูกตัดออก
Tip! การใช้ Thonny หากพบว่าการ run ตรงด้วยการคลิก icon run แล้วเจอ Memory Error หรือ ImportError: cannot import name CayenneLPP ให้เปลี่ยนวิธีการ run เป็น save เป็นไฟล์ code.py แล้วกด Ctrl-D แทน
ข้อความ Error ที่พบเมื่อคลิก Icon Run ไม่ได้ เช่น
Adafruit CircuitPython 5.3.1 on 2020–07–13; SparkFun SAMD21 Mini Breakout with samd21g18
>>> %Run -c $EDITOR_CONTENT
Traceback (most recent call last):
File “<stdin>”, line 6, in <module>
MemoryError:
หรือ error
%Run -c $EDITOR_CONTENT
Traceback (most recent call last):
File “<stdin>”, line 6, in <module>
ImportError: cannot import name CayenneLPP
หมายเหตุ
- ใช้ import adafruit_binascii แทน import ubinascii
2. บอร์ด SAMD21 ของ RobotDyn และ Seeed XIAO ก็น่าจะใช้วิธีนี้ได้เช่นกัน
อ่านวิธีได้จากเวป https://wiki.seeedstudio.com/Seeeduino-XIAO-CircuitPython/ เนื่องจากต้องมีการ Short ขา RST ด้วย
Reference