Installing CircuitPython on Arduino MKR WIFI

Part I: Installing CircuitPython

In this part, we will be flashing two bootloaders sequentially onto MKR.

1. Download and install the latest Arduino IDE https://www.arduino.cc/en/Main/Software
2. Open the IDE. Go to Tools -> Boards -> Boards Manager. In Boards Manager, search "Arduino SAMD Boards (32-bits AMR Cortex-M0+)" and then click Install. After installation, select Tools -> Boards -> MKR WIFI 1010
3. Plug-in MKR WIFI into the computer via a USB cable, and select Tools -> Port -> MKR WIFI or the only USB device when MKR is plugged in.
4. Download latest INO for MKR Zero's bootloader from https://github.com/adafruit/uf2-samdx1/releases to your computer, e.g., https://github.com/adafruit/uf2-samdx1/releases/download/v3.9.0/update-bootloader-mkrzero-v3.9.0.ino
5. Open the INO file just downloaded and upload it to MKR. You should see something like this on your Arduino IDE:

Sketch uses 21112 bytes (8%) of program storage space. Maximum is 262144 bytes.
Global variables use 3464 bytes of dynamic memory.
Atmel SMART device 0x10010005 found
Device : ATSAMD21G18A
Chip ID : 10010005
Version : v2.0 [Arduino:XYZ] Mar 19 2018 09:45:14
Address : 8192
Pages : 3968
Page Size : 64 bytes
Total Size : 248KB
Planes : 1
Lock Regions : 16
Locked : none
Security : false
Boot Flash : true
BOD : true
BOR : true
Arduino : FAST_CHIP_ERASE
Arduino : FAST_MULTI_PAGE_WRITE
Arduino : CAN_CHECKSUM_MEMORY_BUFFER
Erase flash
done in 0.823 seconds

Write 21112 bytes to flash (330 pages)

[===== ] 19% (64/330 pages)
[=========== ] 38% (128/330 pages)
[================= ] 58% (192/330 pages)
[======================= ] 77% (256/330 pages)
[============================= ] 96% (320/330 pages)
[==============================] 100% (330/330 pages)
done in 0.128 seconds

Verify 21112 bytes of flash with checksum.
Verify successful
done in 0.018 seconds
CPU reset.


6. MKR will restart. If not, press the reset button. A USB storage device called MKRZEROBOOT shall pop-up on your computer now. If a file called
CURRENT.UF2
is there, then you are good.

7. Download the CircuitPython image for MKR from https://circuitpython.org/board/arduino_mkrzero/, the UF2 file. Then copy it to the MKRZEROBOOT device. Then the MKR will restart and the new USB storage device's name will become CIRCUITPY. If it doesn't restart automatically, press the reset button.


Part II: Play around with CircuitPython

1. Download and install Mu editor. For Windows and Mac, go to https://codewith.mu/en/download . For Linux, or Python on other platforms, you can simply use pip: pip3 install mu-editor --user Then start the Mu editor.

2. Upon initial start, select "Adafruit CircuitPython". Then you see an blank editor. Now, click the "Serial" button at the top of the window. And you shall see the "Adafruit CircuitPython REPL" box. Click in it, and press any key to activate the Python console. Then, you can enjoy the Python shell.

3. To run a script, in the Mu editor, paste the code below and save it as a file on your CIRCUITPY storage device and make sure it is the only file there. After saving, the MKR will restart on its own -- if not, press the reset button. And you shall see the orange LED blinking.

import board
import digitalio
import time

led = digitalio.DigitalInOut(board.D6)
led.direction = digitalio.Direction.OUTPUT

while True:
print("Hello, CircuitPython!")
led.value = True
time.sleep(1)
led.value = False
time.sleep(1)


Note that the interactive mode Python shell and the scripting mode (i.e., running code from a script file) cannot coexist.

Different Doesn’t Mean Wrong!

I just realize that the East Asian culture has an anti-diversity or pro-orthodoxy part, kinda like monotheism. For thousands of years, kings heavily prompted only one philosophy, the Confucianism. Other ideas were considered unorthodox and eventually marginalized. So, East Asian cultures lack the mechanism of tolerating different options. In this sense, East Asia today, or even East Asian communities in the Western World, share something with Medieval Europe where anyone who said differently to the Pope's teaching were burned, exiled, banned from owning properties, etc. It happened to me several times that some Chinese American, or Chinese Chinese, friends broke up with me on professional things, e.g., terminating research collaboration, because I said something about the Chinese Communist Party that they disagreed -- there was no debate, i just posted on FB/TW. Because no one is holy and no one monopolies the truth, it's better to live with, and to enjoy different opinions. I am very proud of my culture heritage. But the pro-orthodoxy or "solo-truth" mentality, is something I do not agree -- hey, I do not say it is wrong nor do I hate my background. Happy Asian Pacific American Heritage Month of 2020!

我突然意識到東亞文化是一種容不得異見的文化。你看韓國,所謂民主,前總統會被後總統搞死,不止一次了。在美國,敗選的政治人物無所謂,前總統不會被搞死。在東亞,幾千年的「罷黜百家,獨尊儒術」,使東亞人民相信,很多事情只有一個正解,其他都是錯的. 所以,若兩人觀點不同,只有兩種可能: a) 你是SB,腦殘,無腦,etc. b) 你是大逆不道,我不和你寫paper,不和你開公司,不和你在一個team,甚至把政治觀點帶到performance review中. 絕對不可能兩人都是對的或者錯的。東亞人民還活在中世紀的歐洲,和教皇意見相左的人士被燒死,被流放,被不能擁有房產,不能上大學,etc.

Jupyter server OSError: [Errno 99] Cannot assign requested address

If you run into this error:
OSError: [Errno 99] Cannot assign requested address
a likely fix is going to /etc/hosts and pointing localhost only to ipv4 loopback (127.0.0.1), not to ipv6's (::1).

For example, on my computer, /etc/hosts looks like this:

127.0.0.1       localhost

# The following lines are desirable for IPv6 capable hosts
::1     localhost       ip6-localhost   ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

xxx.xxx.xxx.xxx  tinyai  tinyai

Just change it to


127.0.0.1       localhost

# The following lines are desirable for IPv6 capable hosts
::1           ip6-localhost   ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

xxx.xxx.xxx.xxx  tinyai  tinyai

Note the change at the ::1 line.

For more details, read https://github.com/ipython/ipython/issues/6193#issuecomment-466082026

Python lists as local variables in recursion

Today I ran into a really interesting problem. Let's use Leetcode's Problem 77 combination as an example. I wanted write a function that prints all possible combinations (no order, unlike permutation).

So here is my function definition and call:
def helper(n, k, start, L):
    # L = list (L)  # make a copy 
    if len(L) == k:# all k elements have been drawn
        print L
    else:
        for i in range(start, n+1): 
            L.append(i)
            print "L before recursion", l
            helper(n,k,i+1, L) # down to next level
            print "L after recursion", l
            L = L[:-1] 

helper(3,2,1, []) # picking 2 from 3


But this was what I got:
L before recursion [1]
L before recursion [1, 2]
[1, 2]
L after recursion [1, 2]
L before recursion [1, 3]
[1, 3]
L after recursion [1, 3]   
L after recursion [1, 2]  --- l is supposed to be [1] here as quitting the inner recursion 
L before recursion [1, 2]
[1, 2]
L after recursion [1, 2]
L before recursion [1, 3]
[1, 3]
L after recursion [1, 3]

As you can see, L never came back to [1]. It became (at the 8th line of the print-out) [1,2] after executing helper(3,2,2, [1]). Further, there are unmatching numbers of "before" and "after" which made no sense to me.

It took me a couple of hours to think until I realized that maybe the reference of a list was the culprit. So I uncommented the "make a copy" line, and then things worked as expected:
L before recursion [1]
L before recursion [1, 2]
[1, 2]
L after recursion [1, 2]
L before recursion [1, 3]
[1, 3]
L after recursion [1, 3]
L after recursion [1]
L before recursion [2]
L before recursion [2, 3]
[2, 3]
L after recursion [2, 3]
L after recursion [2]
L before recursion [3]
L after recursion [3]

But I still had no clue why a copy fixed it, and even the in-and-out of recursions.
If you know why, let me know.

PS: An alternative fix is to let the function to return L[:-1]. In this way, the old l can be restored after a recursive call.

The evil and immoral cruise line business

I had my first cruise trip not long ago. It wasn't a pleasant experience. The food was good. The room was good. The view was good. So why wasn't it pleasant? The way that the service staff were treated by the company.

The food and stateroom service staff were talking to me as if I was the king and they were my peasants. I couldn't stand it. They acted like people who were not as equal as me, but inferior to me. I speculated that the company put lots of pressure on them to behave like that. I'd feel more comfortable should they interacted with me like how American hospitality works interact with me.

Now I feel morally wrong to take cruise trips. I wish the cruise companies could behave as hiring someone on American soil, e.g., a McDonald's garnisher. Technically, the cruise was on US water. So I don't know why they were treated so badly.