Printed Circuit Boards and Android
A Love Story Between Two Engineering Disciplines
The idea: A digital die
- 🎲 for role playing (d6), board games, general fun
- Run it through a microchip
- Learn about PCBs and how to program them
- How to connect it to an Android app?
🍞 Breadboards 🍞
- Great for testing ideas and debuging
- Horizontal sockets are connected
- Use wires and cable bridges to connect to sockets
- (Relatively) cheap, dynamic, fast iteration
- Too big for final "product"
Perfboards
- Permanent
- Requires soldering
- Reduced size
PCBs
Printed Circuit Boards
- Can create complete board (holes, connections, placements)
- Custom shapes possible
- Use software to define connections and placements
- No soldering needed
- Place connections like lines in a vector program
- Select different layers for back / front / inside
- Texts and shape importer
- Great library of parts (LEDs, resistors, buttons, ICs, MCUs, …)
Preview in 3D
Good for visual checking
- Cheap
- Places parts
- Cuts parts
- Drilling of holes
- Different PCB base colors
- Can be exported from easyeda
Outcome
- 3 different versions created
- All arrived within a couple of weeks of ordering
- Great feeling on seeing your product come to life
SMD vs TH
- (Surface Mounted Device vs Through Hole)
- Why 3 editions though?
- How to debug SMDs without heat bed, hot air gun, …
- What to do on errors? (see first iteration(s))
> Through hole components on board, only wiring by printing service (3rd)
👨💻 Let's see some code 👩💻
- Firmware
- Software for Hardware
Circuit Python
- Python on a chip
- Supports a lot of hardware already
- Plug and Play: USB storage device with code
- ✅
Circuit Python
Hello World for hardware: 💡
Setup Code:
import time
import board
from digitalio import DigitalInOut, Direction
A = DigitalInOut(board.A0)
A.direction = Direction.OUTPUT
Circuit Python
Running forever:
while(True):
A.value = True
time.sleep( 0.3 )
A.value = False
time.sleep( 0.3 )
Show Blinking
Hello World!
- Enough to get started
- Combination of lights == 🎲
😍 Communication: Talk to a chip 🤖
Serial Console
- App writes text to serial
- Chip reads text from serial
- We need an own protocol
Python Firmware Setup
- Enable 2nd serial device
- First for debug (REPL)
- Second for communication with app
boot.py
- Executed on hard reset
- Place to configure
- ⚠️ Don't disable console without fallback. ⚠️
import usb_cdc
usb_cdc.enable(console=True, data=True)
code.py
Serial communication: Python side
import usb_cdc
# …
line = str(usb_cdc.data.readline(), 'utf-8')
if line == "light on":
A.value = True
elif line == "light off":
A.value = False
🐧 Linux calling Circuit Python 🐧
or: how to test the communication?
echo 'light on' > /dev/ttyACM1
echo 'light off' > /dev/ttyACM1
🍎 macOS: different device name 🍎
🗗 Windows: %INSERT_INSTRUCTIONS% 🗗
Android Serial Communication
📈📉🤦🤔🔒😅
USB Device Discovery
val manager : UsbManager =
context.getSystemService(
Context.USB_SERVICE
) as UsbManager
USB Device Discovery
val xiao : UsbDevice = manager
.deviceList // actually: It is a map 😸
.values
.first { device ->
device.productName == "Seeeduino XIAO"
// and more …
}
Finding the Right™ Device
- 😵💫
- 😸 I can haz collections? (iteration through getCount and getId) 😸
Connecting to the Device
USB device permissions:
if (!manager.hasPermission(xiao)) {
// …
}
Connecting to the Device
Create Pending Intent
val intent = PendingIntent.getBroadcast(
context,
0,
Intent(ACTION_USB_PERMISSION),
PendingIntent.FLAG_IMMUTABLE or
PendingIntent.FLAG_ONE_SHOT
)
Connecting to the Device
Tie it together:
val filter = IntentFilter(ACTION_USB_PERMISSION)
context.registerReceiver(usbReceiver, filter)
manager.requestPermission(xiao, intent)
Connecting to the Device
With the permission, the device can be opened:
val connection = manager.openDevice(xiao)
Connecting to the Device
The payload (bytes) created:
val bulkData = "light on\n".toByteArray()
Connecting to the Device
And finally sent:
val result = connection.bulkTransfer(
endpoint, // mind the direction!
bulkData,
bulkData.size,
3_000 // timeout
)
(result == number of bytes send)
All together
val manager : UsbManager =
context.getSystemService(
Context.USB_SERVICE
) as UsbManager
val xiao : UsbDevice = manager
.deviceList
.values
.first { device ->
device.productName == "Seeeduino XIAO"
// and more …
}
if (!manager.hasPermission(xiao)) {
val intent = PendingIntent.getBroadcast(
context,
0,
Intent(ACTION_USB_PERMISSION),
PendingIntent.FLAG_IMMUTABLE or
PendingIntent.FLAG_ONE_SHOT
)
val filter = IntentFilter(ACTION_USB_PERMISSION)
context.registerReceiver(usbReceiver, filter)
manager.requestPermission(xiao, intent)
}
All together
else {
val connection = manager.openDevice(xiao)
val bulkData = "light on\n".toByteArray()
val result = connection.bulkTransfer(
endpoint,
bulkData,
bulkData.size,
3_000 // timeout
)
}
👨💻+⌛+🤔=♥️
🗒️ Notes for Architecture 🏗️
- PCB communication similar to backend
- but needs Android (USBDevice, Permissions)
- layer between VM and repository
- hard to be tested
- 🤔
✅
Further Ideas
- Xigbee on Android
- Control Ikea lamp from your phone?
- IR camera?
- Is the food in the oven hot enough?
- Seeing in the dark?
- ….
- More dice🎲
- Manipulate / Improve dice rolls from phone? 👿
Thanks to
Mobimeo
♥️ And you ♥️
Come and find me, I might have a PCB for you to get started.
😱🙊
💫
HID
What if I press a button on the chip and it sends keyboard codes to the app?
- Xiao can be programmed to mimic a keyboard
- Can send any keyboard commands (🤔)
- Uses hardware keyboard on Android
Python Keyboard Firmware
code.py
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keycode import Keycode
import usb_hid
kbd = Keyboard(usb_hid.devices)
kbd.send(Keycode.A)
# 🌟
Android Keyboard Handling in Activity
Activity.kt
override fun onKeyUp(keyCode: Int, event: KeyEvent)
: Boolean {
return if(
event.device.name == "Seeed Seeeduino XIAO" &&
event.keyCode == KEYCODE_A) {
// 🌟
true
} else {
super.onKeyUp(keyCode, event)
}
}
Result: Clicking Switches influences Android
- One click, one key event
- Different switches -> Different events?
- What else could we build with that?
🧹
Clean PCB communication
- Code samples here are dirty
- Use Clean separation of code:
- Use Repository for communication with PCB
- Device Discovery should be part of Repository too
- Abstract into use cases
- Use View Model to use UseCases
- Hand keyboard events to VM
- C++ (+ some abstractions)
- The default for MCU / DiY / hobbyist(?) programming
- Abstracts compiling to different platforms
- 😢 Needs compilation
- 😢 Arduino IDE is behind IDEA, but useable.
- 😥 Resets chip on code upload, sometimes doesn't connect again
The Code
void setup() {
pinMode(LED_1, OUTPUT);
}
void loop() {
digitalWrite(LED_1, HIGH);
delay(300);
digitalWrite(LED_1, LOW);
delay(300);
}
🐍
Easy/User mode: Changing python code
- buy and install Microsoft exFAT for USB by Paragon
- install Total Commander
- edit python code.py script on the go
- save, upload, works(ish).
- 😢 not very user friendly
- 😥 not very developer friendly
🥷 BACKUP AND VISSUALS, PLEASE IGNORE 🥷