{"id":17107,"date":"2022-11-04T22:49:07","date_gmt":"2022-11-05T02:49:07","guid":{"rendered":"https:\/\/scruss.com\/blog\/?p=17107"},"modified":"2022-11-14T22:41:42","modified_gmt":"2022-11-15T03:41:42","slug":"micropython-on-the-seeed-studio-wio-terminal-it-works","status":"publish","type":"post","link":"https:\/\/scruss.com\/blog\/2022\/11\/04\/micropython-on-the-seeed-studio-wio-terminal-it-works\/","title":{"rendered":"MicroPython on the Seeed Studio Wio Terminal: it works!"},"content":{"rendered":"\n<p>A while back, Seeed Studio sent me one of their Wio Terminal devices to review. It was pretty neat, but being limited to using Arduino to access all of it features was a little limiting. I still liked it, though, and wrote about it here: <a href=\"https:\/\/scruss.com\/blog\/2021\/02\/10\/seeedstudio-wio-terminal\/\">SeeedStudio Wio Terminal<\/a><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"835\" src=\"https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2021\/02\/wioterm-1024x835.jpg\" alt=\"Small screen device showing geometric pattern\" class=\"wp-image-16600\" srcset=\"https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2021\/02\/wioterm-1024x835.jpg 1024w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2021\/02\/wioterm-320x261.jpg 320w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2021\/02\/wioterm-160x130.jpg 160w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2021\/02\/wioterm-768x626.jpg 768w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2021\/02\/wioterm.jpg 1200w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Wio Terminal, doing a thing<\/figcaption><\/figure>\n\n\n\n<p>There wasn&#8217;t any proper MicroPython support for the device as it used a MicroChip\/Atmel SAMD51 ARM\u00ae Cortex\u00ae-M4 micro-controller. But since I wrote the review, one developer (<a href=\"https:\/\/github.com\/robert-hh\">robert-hh<\/a>) has worked almost entirely solo to make SAMD51 and SAMD21 support useful in mainline MicroPython.<\/p>\n\n\n\n<p class=\"has-text-color\" style=\"color:#ff0000\"><strong>Hey!<\/strong> Development is still somewhere between \u201c<em>not quite ready for prime time<\/em>\u201d and \u201c<em>beware of the leopard<\/em>\u201d. MicroPython on the SAMD51 works remarkably well for supported boards, but don&#8217;t expect this to be beginner-friendly yet.<\/p>\n\n\n\n<p>I thought I&#8217;d revisit the Wio Terminal and see what I could do using a nightly build (downloaded from <a href=\"https:\/\/micropython.org\/download\/SEEED_WIO_TERMINAL\/\">Downloads &#8211; Wio Terminal D51R<\/a> &#8211; M<a href=\"https:\/\/micropython.org\/download\/SEEED_WIO_TERMINAL\/\">icroPython<\/a>). Turns out, most of the board works really well!<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What doesn&#8217;t work yet<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Networking\/Bluetooth<\/strong> &#8211; this is never going to be easy, especially with Seeed Studio using a separate <a href=\"https:\/\/www.realtek.com\/en\/products\/communications-network-ics\/item\/rtl8720cm\">RTL8720<\/a> SoC. It may not be entirely impossible, as previously thought, but so far, wifi support seems quite far away<\/li>\n\n\n\n<li><strong>QSPI flash for program storage<\/strong> &#8211; <s>this is not impossible, just not implemented yet<\/s> this works now too, but it&#8217;s quite slow since it relies on a software SPI driver. More details: <a href=\"https:\/\/github.com\/orgs\/micropython\/discussions\/9838#discussioncomment-4090184\">samd51: MicroPython on the Seeed Wio Terminal \u00b7 Discussion #9838 \u00b7 micropython<\/a><\/li>\n\n\n\n<li><strong>RTC<\/strong> &#8211; <s>this is a compile-time option, but isn&#8217;t available on the stock images. Not all SAMD51 boards have a separate RTC oscillator, and deriving the RTC from the system oscillator would be quite wobbly.<\/s> RTC works now! It may even be possible to provide backup battery power and have it keep time when powered off. VBAT \/ PB03 \/ SPI_SCK is broken out to the 40-pin connector.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">What does work<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Display<\/strong> &#8211; ILI9341 320\u00d7240 px, RGB565 via SPI<\/li>\n\n\n\n<li><strong>Accelerometer<\/strong> &#8211; LIS3DHTR via I\u00b2C<\/li>\n\n\n\n<li><strong>Microphone<\/strong> &#8211; analogue<\/li>\n\n\n\n<li><strong>Speaker<\/strong> &#8211; more like a buzzer, but this little PWM speaker element does allow you to play sounds<\/li>\n\n\n\n<li><strong>Light Sensor<\/strong> &#8211; via analogue photo diode<\/li>\n\n\n\n<li><strong>IR emitter<\/strong> &#8211; PWM, not tied to any hardware protocol<\/li>\n\n\n\n<li><strong>Internal LED<\/strong> &#8211; a rather faint blue thing, but useful for low-key signalling<\/li>\n\n\n\n<li><strong>Micro SD Card<\/strong> &#8211; vi SPI. Works well with MicroPython&#8217;s built-in virtual file systems<\/li>\n\n\n\n<li><strong>Switches and buttons<\/strong> &#8211; three buttons on the top, and a five-way mini-joystick<\/li>\n\n\n\n<li><strong>I\u00b2C via Grove Connector<\/strong> &#8211; a second, separate I\u00b2C channel.<\/li>\n<\/ul>\n\n\n\n<p>I&#8217;ll go through each of these here, complete with a small working example.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"820\" src=\"https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2022\/10\/wio_terminal_inside-1024x820.jpg\" alt=\"Wio Terminal main board\" class=\"wp-image-17108\" srcset=\"https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2022\/10\/wio_terminal_inside-1024x820.jpg 1024w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2022\/10\/wio_terminal_inside-320x256.jpg 320w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2022\/10\/wio_terminal_inside-160x128.jpg 160w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2022\/10\/wio_terminal_inside-768x615.jpg 768w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2022\/10\/wio_terminal_inside.jpg 1328w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Inside the remarkably hard-to-open Wio Terminal<\/figcaption><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">LED<\/h3>\n\n\n\n<p>Let&#8217;s start with the simplest feature: the tiny blue LED hidden inside the case. You can barely see this, but it glows out around the USB C connector on the bottom of the case.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>MicroPython interfaces<\/strong>: machine.Pin, machine.PWM<\/li>\n\n\n\n<li><strong>Control pin<\/strong>: Pin(&#8220;LED_BLUE&#8221;) or Pin(15), or Pin(&#8220;PA15&#8221;): any one of these would work.<\/li>\n<\/ul>\n\n\n\n<p>Example: <a href=\"https:\/\/github.com\/scruss\/WioTerminal-MicroPython\/blob\/main\/Wio-Terminal-LED.py\">Wio-Terminal-LED.py<\/a><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n# MicroPython \/ Seeed Wio Terminal \/ SAMD51\n# Wio-Terminal-LED.py - blink the internal blue LED\n# scruss, 2022-10\n# -*- coding: utf-8 -*-\n\nfrom machine import Pin\nfrom time import sleep_ms\n\nled = Pin(&quot;LED_BLUE&quot;, Pin.OUT)  # or Pin(15) or Pin(&quot;PA15&quot;)\n\ntry:\n    while True:\n        led.value(not led.value())\n        sleep_ms(1200)\nexcept:\n    led.value(0)  # turn it off if user quits\n    exit()\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\">IR LED<\/h3>\n\n\n\n<p>I don&#8217;t have any useful applications of the IR LED for device control, so check out <a href=\"https:\/\/awesome-micropython.com\/#ir\">Awesome MicroPython&#8217;s IR section<\/a> for a library that would work for you.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>MicroPython interfaces<\/strong>: machine.PWM<\/li>\n\n\n\n<li><strong>Control pin<\/strong>: Pin(&#8220;PB31&#8221;)<\/li>\n<\/ul>\n\n\n\n<p>Example: <a href=\"https:\/\/github.com\/scruss\/WioTerminal-MicroPython\/blob\/main\/Wio-Terminal-IR_LED.py\">Wio-Terminal-IR_LED.py<\/a><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n# MicroPython \/ Seeed Wio Terminal \/ SAMD51\n# Wio-Terminal-IR_LED.py - blink the internal IR LED\n# scruss, 2022-10\n# -*- coding: utf-8 -*-\n\n# Hey! This is a completely futile exercise, unless you&#039;re able\n# to see into the IR spectrum. But we&#039;re here to show you the pin\n# specification to use. For actual useful libraries to do stuff with\n# IR, take a look on https:\/\/awesome-micropython.com\/#ir\n\n# So this is a boring blink, &#039;cos we&#039;re keeping it short here.\n# You might be able to see the LED (faintly) with your phone camera\n\nfrom machine import Pin, PWM\nfrom time import sleep_ms\n\nir = PWM(Pin(&quot;PB31&quot;))  # &quot;IR_CTL&quot; not currently defined\n\ntry:\n    while True:\n        ir.duty_u16(32767)  # 50% duty\n        ir.freq(38000)  # fast flicker\n        sleep_ms(1200)\n        ir.duty_u16(0)  # off\n        sleep_ms(1200)\nexcept:\n    ir.duty_u16(0)  # turn it off if user quits\n    exit()\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\">Buttons<\/h3>\n\n\n\n<p>There are three buttons on top, plus a 5-way joystick on the front. Their logic is inverted, so they read 0 when pressed, 1 when not. It&#8217;s probably best to use <a href=\"https:\/\/docs.micropython.org\/en\/v1.19.1\/library\/machine.Signal.html?highlight=signal#class-signal-control-and-sense-external-i-o-devices\">machine.Signal<\/a> with these to make operation more, well, <em>logical<\/em>.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>MicroPython interface<\/strong>: machine.Signal (or machine.Pin)<\/li>\n\n\n\n<li><strong>Control pins<\/strong>: Pin(&#8220;BUTTON_3&#8221;) or Pin(92) or Pin(PC28) &#8211; top left; Pin(&#8220;BUTTON_2&#8221;) or Pin(91) or Pin(PC27) &#8211; top middle; Pin(&#8220;BUTTON_1&#8221;) or Pin(90) or Pin(PC26) &#8211; top right; Pin(&#8220;SWITCH_B&#8221;) or Pin(108) or Pin(PD12) &#8211; joystick left; Pin(&#8220;SWITCH_Y&#8221;) or Pin(105) or Pin(PD09) &#8211; joystick right; Pin(&#8220;SWITCH_U&#8221;) or Pin(116) or Pin(PD20) &#8211; joystick up; Pin(&#8220;SWITCH_X&#8221;) or Pin(104) or Pin(PD08) &#8211; joystick down; Pin(&#8220;SWITCH_Z&#8221;) or Pin(106) or Pin(PD10) &#8211; joystick button<\/li>\n<\/ul>\n\n\n\n<p>Example: <a href=\"https:\/\/github.com\/scruss\/WioTerminal-MicroPython\/blob\/main\/Wio-Terminal-Buttons.py\">Wio-Terminal-Buttons.py<\/a><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n# MicroPython \/ Seeed Wio Terminal \/ SAMD51\n# Wio-Terminal-Buttons.py - test the buttons\n# scruss, 2022-10\n# -*- coding: utf-8 -*-\n\n# using Signal because button sense is inverted: 1 = off, 0 = on\nfrom machine import Pin, Signal\nfrom time import sleep_ms\n\npin_names = &#x5B;\n    &quot;BUTTON_3&quot;,  # Pin(92)  or Pin(PC28) - top left\n    &quot;BUTTON_2&quot;,  # Pin(91)  or Pin(PC27) - top middle\n    &quot;BUTTON_1&quot;,  # Pin(90)  or Pin(PC26) - top right\n    &quot;SWITCH_B&quot;,  # Pin(108) or Pin(PD12) - joystick left\n    &quot;SWITCH_Y&quot;,  # Pin(105) or Pin(PD09) - joystick right\n    &quot;SWITCH_U&quot;,  # Pin(116) or Pin(PD20) - joystick up\n    &quot;SWITCH_X&quot;,  # Pin(104) or Pin(PD08) - joystick down\n    &quot;SWITCH_Z&quot;,  # Pin(106) or Pin(PD10) - joystick button\n]\n\npins = &#x5B;None] * len(pin_names)\nfor i, name in enumerate(pin_names):\n    pins&#x5B;i] = Signal(Pin(name, Pin.IN), invert=True)\n\nwhile True:\n    for i in range(len(pin_names)):\n        print(pins&#x5B;i].value(), end=&quot;&quot;)\n    print()\n    sleep_ms(100)\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\">Buzzer<\/h3>\n\n\n\n<p>A very quiet little PWM speaker.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>MicroPython interfaces<\/strong>: machine.PWM<\/li>\n\n\n\n<li><strong>Control pin<\/strong>: Pin(&#8220;BUZZER&#8221;) or Pin(107) or Pin(&#8220;PD11&#8221;)<\/li>\n<\/ul>\n\n\n\n<p>Example: <a href=\"https:\/\/github.com\/scruss\/WioTerminal-MicroPython\/blob\/main\/Wio-Terminal-Buzzer.py\">Wio-Terminal-Buzzer.py<\/a><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n# MicroPython \/ Seeed Wio Terminal \/ SAMD51\n# Wio-Terminal-Buzzer.py - play a scale on the buzzer with PWM\n# scruss, 2022-10\n# -*- coding: utf-8 -*-\n\nfrom time import sleep_ms\nfrom machine import Pin, PWM\n\npwm = PWM(Pin(&quot;BUZZER&quot;, Pin.OUT))  # or Pin(107) or Pin(&quot;PD11&quot;)\ncmaj = &#x5B;262, 294, 330, 349, 392, 440, 494, 523]  # C Major Scale frequencies\n\nfor note in cmaj:\n    print(note, &quot;Hz&quot;)\n    pwm.duty_u16(32767)  # 50% duty\n    pwm.freq(note)\n    sleep_ms(225)\n    pwm.duty_u16(0)  # 0% duty - silent\n    sleep_ms(25)\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\">Light Sensor<\/h3>\n\n\n\n<p>This is a simple photo diode. It doesn&#8217;t seem to return any kind of calibrated value. Reads through the back of the case.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>MicroPython interfaces<\/strong>: machine.ADC<\/li>\n\n\n\n<li><strong>Control pin<\/strong>: machine.ADC(&#8220;PD01&#8221;)<\/li>\n<\/ul>\n\n\n\n<p>Example code: <a href=\"https:\/\/github.com\/scruss\/WioTerminal-MicroPython\/blob\/main\/Wio-Terminal-LightSensor.py\">Wio-Terminal-LightSensor.py<\/a><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n# MicroPython \/ Seeed Wio Terminal \/ SAMD51\n# Wio-Terminal-LightSensor.py - print values from the light sensor\n# scruss, 2022-10\n# -*- coding: utf-8 -*-\n\nfrom time import sleep_ms\nfrom machine import ADC\n\n# PD15-22C\/TR8 photodiode\nlight_sensor = ADC(&quot;PD01&quot;)\n\nwhile True:\n    print(&#x5B;light_sensor.read_u16()])\n    sleep_ms(50)\n<\/pre><\/div>\n\n\n<h2 class=\"wp-block-heading\">Microphone<\/h2>\n\n\n\n<p>Again, a simple analogue sensor:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>MicroPython interfaces<\/strong>: machine.ADC<\/li>\n\n\n\n<li><strong>Control pin<\/strong>: machine.ADC(&#8220;MIC&#8221;)<\/li>\n<\/ul>\n\n\n\n<p>Example: <a href=\"https:\/\/github.com\/scruss\/WioTerminal-MicroPython\/blob\/main\/Wio-Terminal-Microphone.py\">Wio-Terminal-Microphone.py<\/a><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n# MicroPython \/ Seeed Wio Terminal \/ SAMD51\n# Wio-Terminal-Microphone.py - print values from the microphone\n# scruss, 2022-10\n# -*- coding: utf-8 -*-\n\nfrom time import sleep_ms\nfrom machine import ADC\n\nmic = ADC(&quot;MIC&quot;)\n\nwhile True:\n    print(&#x5B;mic.read_u16()])\n    sleep_ms(5)\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\">Grove I\u00b2C Port<\/h3>\n\n\n\n<p>The Wio Terminal has two <a href=\"https:\/\/www.seeedstudio.com\/category\/Grove-c-1003.html\">Grove<\/a> ports: the one on the left (under the speaker port) is an I\u00b2C port. As I don&#8217;t know what you&#8217;ll be plugging in there, this example does a simple bus scan. You could make a, <a href=\"https:\/\/scruss.com\/blog\/2021\/06\/02\/cardkb-mini-keyboard-with-micropython\/\">appalling typewriter<\/a> if you really wanted.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>MicroPython interfaces<\/strong>: machine.I2C (channel 3), machine. Pin<\/li>\n\n\n\n<li><strong>Control pins<\/strong>: scl=Pin(&#8220;SCL1&#8221;), sda=Pin(&#8220;SDA1&#8221;)<\/li>\n<\/ul>\n\n\n\n<p>Example: <a href=\"https:\/\/github.com\/scruss\/WioTerminal-MicroPython\/blob\/main\/Wio-Terminal-Grove-I2C.py\">Wio-Terminal-Grove-I2C.py<\/a><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n# MicroPython \/ Seeed Wio Terminal \/ SAMD51\n# Wio-Terminal-Grove-I2C.py - show how to connect on Grove I2C\n# scruss, 2022-10\n# -*- coding: utf-8 -*-\n\nfrom machine import Pin, I2C\n\n# NB: This doesn&#039;t do much of anything except list what&#039;s\n# connected to the left (I\u00b2C) Grove connector on the Wio Terminal\n\ni2c = I2C(3, scl=Pin(&quot;SCL1&quot;), sda=Pin(&quot;SDA1&quot;))\ndevices = i2c.scan()\n\nif len(devices) == 0:\n    print(&quot;No I\u00b2C devices connected to Grove port.&quot;)\nelse:\n    print(&quot;Found these I\u00b2C devices on the Grove port:&quot;)\n    for n, id in enumerate(devices):\n        print(&quot; device&quot;, n, &quot;: ID&quot;, id, &quot;(hex:&quot;, hex(id) + &quot;)&quot;)\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\">LIS3DH Accelerometer<\/h3>\n\n\n\n<p>This is also an I\u00b2C device, but connected to a different port (both logically and physically) than the Grove one.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>MicroPython interfaces<\/strong>: machine.I2C (channel 4), machine. Pin<\/li>\n\n\n\n<li><strong>Control pins<\/strong>: scl=Pin(&#8220;SCL0&#8221;), sda=Pin(&#8220;SDA0&#8221;)<\/li>\n\n\n\n<li><strong>Library<\/strong>: from <a href=\"https:\/\/github.com\/tinypico\/tinypico-micropython\/tree\/master\/lis3dh%20library#micropython-lis3dh\">MicroPython-LIS3DH<\/a>, copy <a href=\"https:\/\/github.com\/tinypico\/tinypico-micropython\/blob\/master\/lis3dh%20library\/lis3dh.py\">lis3dh.py<\/a> to the Wio Terminal&#8217;s small file system. Better yet, compile it to mpy using <em>mpy-cross<\/em> to save even more space before you copy it across<\/li>\n<\/ul>\n\n\n\n<p>Example: <a href=\"https:\/\/github.com\/scruss\/WioTerminal-MicroPython\/blob\/main\/Wio-Terminal-Accelerometer.py\">Wio-Terminal-Accelerometer.py<\/a> (based on <a href=\"https:\/\/github.com\/tinypico\/tinypico-micropython\/blob\/master\/lis3dh%20library\/example.py\">tinypico-micropython\/lis3dh library\/example.py<\/a>)<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n# MicroPython \/ Seeed Wio Terminal \/ SAMD51\n# Wio-Terminal-Accelerometer.py - test out accelerometer\n# scruss, 2022-10\n# -*- coding: utf-8 -*-\n# based on\n#  https:\/\/github.com\/tinypico\/tinypico-micropython\/tree\/master\/lis3dh%20library\n\nimport lis3dh, time, math\nfrom machine import Pin, I2C\n\ni2c = I2C(4, scl=Pin(&quot;SCL0&quot;), sda=Pin(&quot;SDA0&quot;))\nimu = lis3dh.LIS3DH_I2C(i2c)\n\nlast_convert_time = 0\nconvert_interval = 100  # ms\npitch = 0\nroll = 0\n\n# Convert acceleration to Pitch and Roll\ndef convert_accell_rotation(vec):\n    x_Buff = vec&#x5B;0]  # x\n    y_Buff = vec&#x5B;1]  # y\n    z_Buff = vec&#x5B;2]  # z\n\n    global last_convert_time, convert_interval, roll, pitch\n\n    # We only want to re-process the values every 100 ms\n    if last_convert_time &lt; time.ticks_ms():\n        last_convert_time = time.ticks_ms() + convert_interval\n\n        roll = math.atan2(y_Buff, z_Buff) * 57.3\n        pitch = (\n            math.atan2((-x_Buff), math.sqrt(y_Buff * y_Buff + z_Buff * z_Buff)) * 57.3\n        )\n\n    # Return the current values in roll and pitch\n    return (roll, pitch)\n\n\n# If we have found the LIS3DH\nif imu.device_check():\n    # Set range of accelerometer (can be RANGE_2_G, RANGE_4_G, RANGE_8_G or RANGE_16_G).\n    imu.range = lis3dh.RANGE_2_G\n\n    # Loop forever printing values\n    while True:\n        # Read accelerometer values (in m \/ s ^ 2).  Returns a 3-tuple of x, y,\n        # z axis values.  Divide them by 9.806 to convert to Gs.\n        x, y, z = &#x5B;value \/ lis3dh.STANDARD_GRAVITY for value in imu.acceleration]\n        print(&quot;x = %0.3f G, y = %0.3f G, z = %0.3f G&quot; % (x, y, z))\n\n        # Convert acceleration to Pitch and Roll and print values\n        p, r = convert_accell_rotation(imu.acceleration)\n        print(&quot;pitch = %0.2f, roll = %0.2f&quot; % (p, r))\n\n        # Small delay to keep things responsive but give time for interrupt processing.\n        time.sleep(0.1)\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\">SD Card<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>MicroPython interfaces<\/strong>: machine.SPI (channel 6), machine.Pin, machine.Signal<\/li>\n\n\n\n<li><strong>Control Pins<\/strong>: Pin(&#8220;SD_SCK&#8221;), Pin(&#8220;SD_MOSI&#8221;), Pin(&#8220;SD_MISO&#8221;) for SD access. Pin(&#8220;SD_DET&#8221;) is low if an SD card is inserted, otherwise high<\/li>\n\n\n\n<li><strong>Library<\/strong>: copy <a href=\"https:\/\/github.com\/micropython\/micropython-lib\/blob\/master\/micropython\/drivers\/storage\/sdcard\/sdcard.py\">sdcard.py<\/a> from micropython-lib to the Wio Terminal&#8217;s file system.<\/li>\n<\/ul>\n\n\n\n<p>Rather than provide a small canned example (there&#8217;s one here, if you must: <a href=\"https:\/\/github.com\/scruss\/WioTerminal-MicroPython\/blob\/main\/Wio-Terminal-SDCard.py\">Wio-Terminal-SDCard.py<\/a>) here&#8217;s my <em>boot.py<\/em> startup file, showing how I safely mount an SD card if there&#8217;s one inserted, but keep booting even if it&#8217;s missing:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n# boot.py - MicroPython \/ Seeed Wio Terminal \/ SAMD51\n\nimport sys\n\nsys.path.append(&quot;\/lib&quot;)\n\nimport machine\nimport gc\nimport os\nimport sdcard\n\nmachine.freq(160000000)  # fast but slightly jittery clock\ngc.enable()\n\n# mount SD card if there&#039;s one inserted\ntry:\n    sd_detected = machine.Signal(\n        machine.Pin(&quot;SD_DET&quot;, machine.Pin.IN),\n        invert=True,\n    )\n    sd_spi = machine.SPI(\n        6,\n        sck=machine.Pin(&quot;SD_SCK&quot;),\n        mosi=machine.Pin(&quot;SD_MOSI&quot;),\n        miso=machine.Pin(&quot;SD_MISO&quot;),\n        baudrate=40000000,\n    )\n    sd = sdcard.SDCard(sd_spi, machine.Pin(&quot;SD_CS&quot;))\n    if sd_detected.value() == True:\n        os.mount(sd, &quot;\/SD&quot;)\n        print(&quot;SD card mounted on \/SD&quot;)\n    else:\n        raise Exception(&quot;SD card not inserted, can&#039;t mount \/SD&quot;)\nexcept:\n    print(&quot;SD card not found&quot;)\n\n\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\">ILI9341 Display<\/h3>\n\n\n\n<p>I&#8217;m going to use the library <a href=\"https:\/\/github.com\/rdagger\/micropython-ili9341\">rdagger\/micropython-ili9341: MicroPython ILI9341Display &amp; XPT2046 Touch Screen Driver<\/a> because it&#8217;s reliable, and since it&#8217;s written entirely in MicroPython, it&#8217;s easy to install. It&#8217;s not particularly fast, though.<\/p>\n\n\n\n<p>The Wio Terminal may have an XPT2046 resistive touch controller installed, but I haven&#8217;t been able to test it. There are LCD_XL, LCD_YU, LCD_XR and LCD_YD lines on the schematic that might indicate it&#8217;s there, though.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>MicroPython interfaces<\/strong>: machine.SPI (channel 7), machine.Pin.<\/li>\n\n\n\n<li><strong>Control Pins<\/strong>: Pin(&#8220;LCD_SCK&#8221;), Pin(&#8220;LCD_MOSI&#8221;), Pin(&#8220;LCD_MISO&#8221;). Pin(&#8220;LED_LCD&#8221;) is the backlight control<\/li>\n\n\n\n<li><strong>Library<\/strong>: copy <a href=\"https:\/\/github.com\/rdagger\/micropython-ili9341\/blob\/master\/ili9341.py\"><\/a><a href=\"https:\/\/github.com\/rdagger\/micropython-ili9341\/blob\/master\/ili9341.py\">ili9341.py<\/a> from rdagger \/micropython-ili9341 to the Wio Terminal&#8217;s file system.<\/li>\n<\/ul>\n\n\n\n<p>This demo draws rainbow-coloured diamond shapes that change continuously.<\/p>\n\n\n\n<p>Example: <a href=\"https:\/\/github.com\/scruss\/WioTerminal-MicroPython\/blob\/main\/Wio-Terminal-Screen.py\">Wio-Terminal-Screen.py<\/a><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n# MicroPython \/ Seeed Wio Terminal \/ SAMD51\n# Wio-Terminal-Screen.py - output something on the ILI9341 screen\n# scruss, 2022-10\n# -*- coding: utf-8 -*-\n\n\nfrom time import sleep\nfrom ili9341 import Display, color565\nfrom machine import Pin, SPI\n\n\ndef wheel565(pos):\n    # Input a value 0 to 255 to get a colour value.\n    # The colours are a transition r - g - b - back to r.\n    # modified to return RGB565 value for ili9341 - scruss\n    (r, g, b) = (0, 0, 0)\n    if (pos &lt; 0) or (pos &gt; 255):\n        (r, g, b) = (0, 0, 0)\n    if pos &lt; 85:\n        (r, g, b) = (int(pos * 3), int(255 - (pos * 3)), 0)\n    elif pos &lt; 170:\n        pos -= 85\n        (r, g, b) = (int(255 - pos * 3), 0, int(pos * 3))\n    else:\n        pos -= 170\n        (r, g, b) = (0, int(pos * 3), int(255 - pos * 3))\n    return (r &amp; 0xF8) &lt;&lt; 8 | (g &amp; 0xFC) &lt;&lt; 3 | b &gt;&gt; 3\n\n\n# screen can be a little slow to turn on, so use built-in\n# LED to signal all is well\nled = Pin(&quot;LED_BLUE&quot;, Pin.OUT)\n\nbacklight = Pin(&quot;LED_LCD&quot;, Pin.OUT)  # backlight is not a PWM pin\nspi = SPI(\n    7, sck=Pin(&quot;LCD_SCK&quot;), mosi=Pin(&quot;LCD_MOSI&quot;), miso=Pin(&quot;LCD_MISO&quot;), baudrate=4000000\n)\ndisplay = Display(spi, dc=Pin(&quot;LCD_D\/C&quot;), cs=Pin(&quot;LCD_CS&quot;), rst=Pin(&quot;LCD_RESET&quot;))\ndisplay.display_on()\ndisplay.clear()\nled.on()  # shotgun debugging, embedded style\nbacklight.on()\n\n# use default portrait settings: x = 0..239, y = 0..319\ndx = 3\ndy = 4\nx = 3\ny = 4\ni = 0\n\ntry:\n    while True:\n        # display.draw_pixel(x, y, wheel565(i))\n        display.fill_hrect(x, y, 3, 4, wheel565(i))\n        i = (i + 1) % 256\n        x = x + dx\n        y = y + dy\n        if x &lt;= 4:\n            dx = -dx\n        if x &gt;= 234:\n            dx = -dx\n        if y &lt;= 5:\n            dy = -dy\n        if y &gt;= 313:\n            dy = -dy\nexcept:\n    backlight.off()\n    led.off()\n    display.display_off()\n<\/pre><\/div>","protected":false},"excerpt":{"rendered":"<p>A while back, Seeed Studio sent me one of their Wio Terminal devices to review. It was pretty neat, but being limited to using Arduino to access all of it features was a little limiting. I still liked it, though, and wrote about it here: SeeedStudio Wio Terminal There wasn&#8217;t any proper MicroPython support for [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[3315,2],"tags":[3094,3316,3256,3257],"class_list":["post-17107","post","type-post","status-publish","format-standard","hentry","category-electronics","category-goatee-stroking-musing-or-something","tag-micropython","tag-samd51","tag-seeed","tag-wio"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/pQNZZ-4rV","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/posts\/17107","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/comments?post=17107"}],"version-history":[{"count":8,"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/posts\/17107\/revisions"}],"predecessor-version":[{"id":17122,"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/posts\/17107\/revisions\/17122"}],"wp:attachment":[{"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/media?parent=17107"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/categories?post=17107"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/tags?post=17107"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}