วิธีติดตั้ง CircuitPython ลงบน Board SAMD21 Mini

Somsak Lima
6 min readJun 29, 2020

--

บอร์ด SAMD21 มีขนาดเล็กกระทัดรัด ราคาค่อนข้างถูกประมาณไม่ถึง 10 US$ ดู Spec SAMD21 เทียบกับ UNO R3 ได้ดังนี้

Source:https://learn.sparkfun.com/tutorials/samd21-minidev-breakout-hookup-guide/all

การลง 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
OK
Hello! #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

หมายเหตุ

  1. ใช้ import adafruit_binascii แทน import ubinascii

2. บอร์ด SAMD21 ของ RobotDyn และ Seeed XIAO ก็น่าจะใช้วิธีนี้ได้เช่นกัน

อ่านวิธีได้จากเวป https://wiki.seeedstudio.com/Seeeduino-XIAO-CircuitPython/ เนื่องจากต้องมีการ Short ขา RST ด้วย

Reference

--

--

Somsak Lima
Somsak Lima

Written by Somsak Lima

สนับสนุนและส่งเสริมให้ผู้สนใจสามารถใช้งานเทคโนโลยี LoRa และ LoRaWAN ได้ โดยนำความรู้ที่ได้ไปต่อยอดเพื่อใช้งาน

No responses yet