Week 13: Embedded Networking and Communications
Download this week's code
Assignment requirements
The first checklist
Design and build a wired &/or wireless network connecting at least two processors
The second checklist: Learning outcomes
- Demonstrate workflows used in network design and construction
- Implement and interpret networking protocols
The thirds checlist: Have you
- Described your design and fabrication process using words/images/screenshots.
- Explained the programming process/es you used.
- Outlined problems and how you fixed them
- Included original design files and code
Preamble - How a collection of forces have been working against me — or — Life happens, all in the same week
My baby son has ear infections in both ears and is on antibiotics. We aren't sleeping much. It's King's Day here in the Netherlands (hooray!). So the Fab Lab is not open late on Thursday evening, and is closed on Friday, the times that I have available to get work done. So, this week is tough.
My final project idea uses networking, but it's serial over USB between a computer and a 3D printer, so I don't need to programme any devices to do protocols or anything. I'm envisioning a Raspberry Pi as the computer, but I suppose there's always time to add a microcontroller somewhere in the mix.
I did flirt with the idea of having a bridge control to node chips with speakers, and having them to two-voice harmony, something like the Palestrina motet, Dona nobis pacem. So I looked into doing sound out of a chip using the Tone library, but then there was confusion about whether Tone works with Attiny84… Did I mention I have a sick baby?
Doing it
I want to keep it modest. Basic asynchronous serial or I2C? I found this page from 2017 with fairly detailed instructions on doing I2C and serial, modelled after Neil's examples. The examples, however, use an ATTiny45, which we haven't been using in the lab, which means I need to either see how the schematics would have to be redrawn for the ATTiny84, and whether the Tinywire library works for the 84. It apparently can, but doesn't necessarily; did I mention that it's King's Day this weekend and everything's closed?
I started to recreate the schematic from Tiang Seih's page, and routing the board, and then I realised that I did just not have enough time to do this before the lab closed. I looked at my boards from previous weeks, and determined that I might be able to use the 6-pin programming header to do asynchronous serial between two boards. So I went home, hoping that I could figure this out with these boards. One has a built-in LED and phototransistor, the others have nothing wired onto them. I could at least get a plain board to have the LED board to blink; or have the LED board send messages to the plain board, and have the plain board echo the messages back and cause the LED to blink; or I could use alligator clips to attach an LED to the plain board. On the train home I'll arrange the code from previous weeks to try and do this.
Here is my untested Arduino code for the bridge. The code imports the sfotwareserial library, intialises a serial object, begins the serial, and then every second prints the numbers 0 and 1.
/* async01bridge serial code
* Fab Academy 2018 at the Waag in Amsterdam.
* Copyeverything, David McCallum, 2018
* sintheta.org
*/
#include <SoftwareSerial.h>
const int FTDIrxPin = 0;
const int FTDItxPin = 1;
const int softRxPin = 8; // these pins based on the 6-pin ISP header
const int softTxPin = 9;
SoftwareSerial serialFTDI(rxPin, txPin);
SoftwareSerial serialSoft(rxPin, txPin);
void setup() {
serialFTDI.begin(9600);
serialSoft.begin(9600);
}
void loop() {
// Send 0 ... 1 ... repeat. No newlines.
serialSoft.print(0);
delay(1000);
serialSoft.print(1);
delay(1000);
}
And here is my untested Arduino code for the node. It imports the softwareserial library. Reads for bytes. If it's a 0 or 1 will turn the LED on or off.
/* async01node serial code
* Fab Academy 2018 at the Waag in Amsterdam.
* Copyeverything, David McCallum, 2018
* sintheta.org
*/
#include <SoftwareSerial.h>
const int FTDIrxPin = 0;
const int FTDItxPin = 1;
const int softRxPin = 9; // these pins based on the 6-pin ISP header
const int softTxPin = 8;
const int photoPin = 2;
const int buttonPin = 3;
const int LEDpin = 7;
int serialByteIn = -1; // storage for the serial input
SoftwareSerial serialFTDI(FTDIrxPin, FTDItxPin);
SoftwareSerial serialSoft(softRxPin, softTxPin);
void setup() {
serialFTDI.begin(9600);
serialSoft.begin(9600);
}
void loop() {
if(serialSoft.available() > 0){
serialByteIn = serialSoft.read();
if (serialByteIn == 1){ digitalWrite(LEDpin, HIGH); } // if it receives a 1 turn the LED on, otherwise turn it off
else {digitalWrite(LEDpin, LOW);}
}
}
I suspect I will run into problems with encoding, such as whether or not I'm reading strings or bytes. I will have to investigate using serial.write() rather than .print().
Here are the boards connected to each other with the FTDI giving power, and Emma requested a schematic of the pinout.
To be honest, I never considered the pinout in the way that it's presented in the schematic. I just knew that if the connector was oriented properly, all the corresponding pins on each ATtiny would match, VCC and GND would ensure power, and the numbered pins would match on both boards (4 connects to 4, for example). All that mattered was that I knew which pins MISO, MOSI, and SCK connected to so that I could assign them correctly in the Arduino code.
First problem, wrong pin numbers. Confusing the chip pin numbers with the Arduino numbers. Consulted the pinouts and corrected. Still no results. I could debug this with an oscilloscope, but I don't have one, so I think this is as far as I get this week.
… and then I tried one last effort… I changed it to serial.write() instead of .print(). Then I had to format the integer as a byte because I was getting the error error: call of overloaded 'write(int)' is ambiguous.
IT WORKS!
Here is the new, working bridge code:
/* async01bridge serial code
* Fab Academy 2018 at the Waag in Amsterdam.
* Copy all the things, David McCallum, 2018
* sintheta.org
*/
// ATMEL ATTINY84 / ARDUINO
//
// +-\/-+
// VCC 1| |14 GND
// (D 10) PB0 2| |13 AREF (D 0)
// (D 9) PB1 3| |12 PA1 (D 1)
// PB3 4| |11 PA2 (D 2)
// PWM INT0 (D 8) PB2 5| |10 PA3 (D 3)
// PWM (D 7) PA7 6| |9 PA4 (D 4)
// PWM (D 6) PA6 7| |8 PA5 (D 5) PWM
#include <SoftwareSerial.h>
const int FTDIrxPin = 0;
const int FTDItxPin = 1;
const int softRxPin = 4; // these pins based on the 6-pin ISP header
const int softTxPin = 5;
SoftwareSerial serialFTDI(FTDIrxPin, FTDItxPin);
SoftwareSerial serialSoft(softRxPin, softTxPin);
void setup() {
serialFTDI.begin(9600);
serialSoft.begin(9600);
}
void loop() {
// Send 0 ... 1 ... repeat. No newlines.
serialSoft.write(byte(0));
serialFTDI.print(0);
delay(1000);
serialSoft.write(byte(1));
serialFTDI.print(1);
delay(1000);
}
And here is the new, working node code:
/* async01node serial code
* Fab Academy 2018 at the Waag in Amsterdam.
* Copy all the things, David McCallum, 2018
* sintheta.org
*/
#include <SoftwareSerial.h>
const int FTDIrxPin = 0;
const int FTDItxPin = 1;
const int softRxPin = 5; // these pins based on the 6-pin ISP header
const int softTxPin = 4;
const int photoPin = 2;
const int buttonPin = 3;
const int LEDpin = 7;
byte serialByteIn = -1; // storage for the serial input
SoftwareSerial serialFTDI(FTDIrxPin, FTDItxPin);
SoftwareSerial serialSoft(softRxPin, softTxPin);
void setup() {
serialFTDI.begin(9600);
serialSoft.begin(9600);
pinMode(LEDpin, OUTPUT);
}
void loop() {
if(serialSoft.available() > 0){
serialByteIn = serialSoft.read();
if (serialByteIn == 1){ digitalWrite(LEDpin, HIGH); } // if it receives a 1 turn the LED on, otherwise turn it off
else {digitalWrite(LEDpin, LOW);}
//digitalWrite(LEDpin, HIGH);
}
//else { digitalWrite(LEDpin, LOW); }
}
There is no explicit network node address in the code, because I only had one node to work with (other than the bridge). However, the "node" is looking for the digit 1, seen in the code if (serialByteIn == 1)
, so it could be considered Node 1. To add more nodes, each node would listen for other numbers (such as (serialByteIn == 2)
, and I would choose numbers that would correspond to each node. This allows for the bridge to trigger each node, but not to send any other kind of information.
And here's the bleep bloop.
Asynchronous serial bleep from David McCallum on Vimeo.