# Feather F405 quickstart Install PlatformIO for you editor of choice - I suggest VScode, but feel free to use Atom, Sublime, Vim or whatever you like. Many editors are supported: https://platformio.org/install/integration We will use DFU to upload the code, so you'll need the DFU udev rules under linux. https://docs.platformio.org/en/latest/faq.html#platformio-udev-rules For MacOS and windows you should be all good. Maybe (I don't use these really so no idea). Again for linux make sure your user is in the dialout group then restart udev ```bash sudo service udev restart ``` :::warning Under linux and MacOS you'll need to install dfu-util. In MacOS it is available via brew Under Windows you'll need to install st's DFU tools. This unfortunatly requires you to create a ST account, which is pain. https://www.st.com/en/development-tools/stm32cubeprog.html ::: ## PlatformIO project prep Open your editor and open platformIO in that - this will likely happen automatically. Create a new project ![](https://i.imgur.com/z0Earpj.png) Call your project blink and pick the feather F405 from the dropdown list of boards. Be careful not to accidentally select the Feather express M4 - it's a SAM chip not the F405 ![](https://i.imgur.com/VezCvM3.png) This will create a folder structure with a bunch of folders and files. The important ones for now are the ```src/main.cpp``` file and the ```platformio.ini``` file in the project root directory. ### ini file adjustments for DFU upload and USB serial We need to adjust the ```platformio.ini``` to use the DFU firmware update method. The file should now look like: ```ini ; PlatformIO Project Configuration File ; ; Build options: build flags, source filter ; Upload options: custom upload port, speed and extra flags ; Library options: dependencies, extra library storages ; Advanced options: extra scripting ; ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html [env:adafruit_feather_f405] platform = ststm32 board = adafruit_feather_f405 framework = arduino upload_protocol = dfu ``` :::warning Unfortunately PlatformIO currently doesn't setup the USB serial correctly for the feather. So we need to add some build flags to the ini file. This will enable ```serial()``` commands to print to a usbserial device. Our final ```platformio.ini``` file will look like: ```ini [env:adafruit_feather_f405] platform = ststm32 board = adafruit_feather_f405 framework = arduino upload_protocol = dfu build_flags = -D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC -D USBCON -D USBD_VID=0x0483 -D USBD_PID=0x5740 -D USB_MANUFACTURER="Adafruit" -D USB_PRODUCT="\"Feather F405\"" ``` ::: ## Blinking the onboard LED The feather f405 board has a build in led next to the USB socket. It's connected to pin 13 of the microcontroller. If you look closely at the board you'll see the LED with the number 13 next to it on the silkscreen. Edit the ```main.cpp``` file to the following. ```cpp #include <Arduino.h> // Which pin on the Feather is conencted to the LED #define MYLED 13 // We could also use the built in def LED_BUILTIN, but we're doing it the long way here. void setup() { // put your setup code here, to run once: // initialize digital pin LED_BUILTIN as an output. pinMode(MY_LED, OUTPUT); } void loop() { // put your main code here, to run repeatedly: digitalWrite(MYLED , HIGH); // turn the LED on (HIGH is the voltage level) delay(1000); // wait for a second digitalWrite(MYLED, LOW); // turn the LED off by making the voltage LOW delay(1000); } ``` The microcontroller will run the setup function once, then run the loop() endlessly. ### Upload the code To upload the code we need to put the microcontroller in DFU mode, which sadly requires us to solder a wire to it. Solder a wire to 3.3v and leave the other end bare to touch to the boot0 pin. If using a breadboard we can also use a jump wire. ![](https://i.imgur.com/o3yy3ub.png) See here for more info: https://learn.adafruit.com/adafruit-stm32f405-feather-express/arduino-ide-setup Touch the 3.3v to the boot0 pin while pressing the reset button on the board (it's the only button) and the board will go into DFU update mode. One you've pressed the reset button, disconnect the 3.3V from the boot0 pin. To compile and upload your code, just click the little upload arrow on the platformIO menu - usually very tiny on the bottom of the screen. ![](https://i.imgur.com/WthcHki.png) It's the little arrow next to the tick. The first time you run this it might take a while as platformIO downloads the toolchains needed for the chosen microcontroller and builds the code. Your led should now be blinking between green and red. :::success #### Exercise Now that you have a blinking led, change the blinking pattern. Try get the led to blink fast twice then two slow blinks. :::spoiler Answer ```cpp #include <Arduino.h> // Which pin on the Feather is conencted to the LED #define MYLED 13 // We could also use the built in def LED_BUILTIN, but we're doing it the long way here. void setup() { // put your setup code here, to run once: // initialize digital pin LED_BUILTIN as an output. pinMode(MYLED, OUTPUT); } void loop() { // put your main code here, to run repeatedly: digitalWrite(MYLED , HIGH); // turn the LED on (HIGH is the voltage level) delay(500); // wait for a second digitalWrite(MYLED, LOW); // turn the LED off by making the voltage LOW delay(500); digitalWrite(MYLED , HIGH); // turn the LED on (HIGH is the voltage level) delay(500); // wait for a second digitalWrite(MYLED, LOW); // turn the LED off by making the voltage LOW delay(500); digitalWrite(MYLED , HIGH); // turn the LED on (HIGH is the voltage level) delay(2000); // wait for a second digitalWrite(MYLED, LOW); // turn the LED off by making the voltage LOW delay(2000); digitalWrite(MYLED , HIGH); // turn the LED on (HIGH is the voltage level) delay(2000); // wait for a second digitalWrite(MYLED, LOW); // turn the LED off by making the voltage LOW delay(2000); } ``` #### Using a function: ```cpp #include <Arduino.h> // Which pin on the Feather is conencted to the LED #define MYLED 13 // We could also use the built in def LED_BUILTIN, but we're doing it the long way here. void blinkfunc(int ledpin, int duration){ digitalWrite(ledpin , HIGH); // turn the LED on (HIGH is the voltage level) delay(duration); // wait for a second digitalWrite(ledpin, LOW); // turn the LED off by making the voltage LOW delay(duration); } void setup() { // initialize digital pin LED_BUILTIN as an output. pinMode(MYLED, OUTPUT); } void loop() { blinkfunc(MYLED, 500); blinkfunc(MYLED, 2000); } ::: :::info #### Extention Exercise What if you want to blink 20 times fast and 10 times slow? Google arduino loops to help. You could also use a function if you like. :::spoiler Answer ```cpp #include <Arduino.h> // Which pin on the Feather is conencted to the LED #define MYLED 13 // We could also use the built in def LED_BUILTIN, but we're doing it the long way here. #define SLOWDURATION 2000 // time for the slow blinks - microseconds #define FASTDURATION 100 // for the fast blinks #define FASTTIMES 20 //number of fast blinks #define SLOWTIMES 5 //number of slow blinks void blinkfunc(int ledpin, int duration){ digitalWrite(ledpin , HIGH); // turn the LED on (HIGH is the voltage level) delay(duration); // wait for a duration digitalWrite(ledpin, LOW); // turn the LED off by making the voltage LOW delay(duration); } void setup() { // initialize digital pin LED_BUILTIN as an output. pinMode(MYLED, OUTPUT); } void loop() { //Loop though from i=0 to i=fasttimes-1 for(int i=0; i<FASTTIMES; i++){ blinkfunc(MYLED, FASTDURATION); } for(int i=0; i<SLOWTIMES; i++){ blinkfunc(MYLED, SLOWDURATION); } } ::: ### Looking Closer at the Blinking project Arduino uses the programming language C. However, it does not have a main() function. The main() function is added to the Arduino library. There are two special functions that are a part of every Arduino program: * **setup()** is called once, when the code starts. It's a good place to do setup tasks like setting pin modes or initialing libraries. * **loop()** function is called over and over and is heart of most programs. You need to include both functions in your code even if you don't need them for anything. The **pinMode** function configures a specified pin for either input (receive data) or output (send data). The function includes two parameters: * **pin:** The number of the pin whose mode you want to set * **mode:** Either *INPUT* or *OUTPUT* The **digitalWrite** function sends a digital value to a pin. The digital pins have only two states: on or off. In electrical terms, these can be referred to as either a *HIGH* or *LOW* value, which is relative to the voltage of theboard. The function includes two parameters: * **pin:** The name or number of the pin whose mode you want to set * **value:** Either *HIGH* or *LOW* **Delay** function does just what it says: It stops the program, in this case for an amount of time in milliseconds. ## Blinking the RGB led Create a new project, called something like ```F405_RGB``` The feather has a nexopixel RGB led on the board, so let's use that to blink colors. Edit the ```main.cpp``` file to the following - it's basically the adafruit neopixel library example edited for a single pixel. ```cpp #include <Arduino.h> // NeoPixel Ring simple sketch (c) 2013 Shae Erisson // Released under the GPLv3 license to match the rest of the // Adafruit NeoPixel library #include <Adafruit_NeoPixel.h> // Which pin on the Arduino is connected to the NeoPixels? #define PIN 8 // How many NeoPixels are attached to the Arduino? #define NUMPIXELS 1 // When setting up the NeoPixel library, we tell it how many pixels, // and which pin to use to send signals. Note that for older NeoPixel // strips you might need to change the third parameter -- see the // strandtest example for more information on possible values. Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); #define DELAYVAL 1000 // Time (in milliseconds) to pause. In this case 1s void setup() { pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED) pixels.clear(); // Set all pixel colors to 'off' } void loop() { // pixels.Color() takes RGB values, from 0,0,0 up to 255,255,255 // Here we're using a dim green color - these things are so bright at max: pixels.setPixelColor(0, pixels.Color(0, 5, 0)); pixels.show(); // Send the updated pixel colors to the hardware. delay(DELAYVAL); // Pause before next pass through loop //Let's use a red pixels.setPixelColor(0, pixels.Color(5, 0, 0)); pixels.show(); // Send the updated pixel colors to the hardware. delay(DELAYVAL); // Pause before next pass through loop } ``` ### Library management Before we can compile this we will need the Adafruit neopixel library, platformIO can handle this for us. Either open the PlatformIO home tab, or if you've closed that, click the little alien face on the left hand tool bar and click Open under the quick access list. ![](https://i.imgur.com/5DMwp7O.png) Now click libraries (don't mind the red 8 on my libraries, it's just letting me know that there are 8 libraries I use with newer versions). ![](https://i.imgur.com/HDQeTkZ.png) Search for neopixel, the adafruit library will come up first (the FastLed library also shows up and is an excellent led library, but I digress). Click the neopixel library and install it. ![](https://i.imgur.com/8jybgUZ.png) Upload the code to the microtroller and check the RGB led blinks between green and red. :::success ### Exercise Try change the example to blink a different pair of colours, how about magenta and cyan? Notice if use use a dim value like 5 you can easily see how the colours are mixed. Investigate the ```setBrightness``` method of the Adafruit_NeoPixel library to simplify managing brightnesss :::spoiler Answer ```cpp #include <Arduino.h> // NeoPixel Ring simple sketch (c) 2013 Shae Erisson // Released under the GPLv3 license to match the rest of the // Adafruit NeoPixel library #include <Adafruit_NeoPixel.h> // Which pin on the Arduino is connected to the NeoPixels? #define PIN 8 // How many NeoPixels are attached to the Arduino? #define NUMPIXELS 1 // When setting up the NeoPixel library, we tell it how many pixels, // and which pin to use to send signals. Note that for older NeoPixel // strips you might need to change the third parameter -- see the // strandtest example for more information on possible values. Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); #define DELAYVAL 1000 // Time (in milliseconds) to pause. In this case 1s void setup() { pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED) pixels.clear(); // Set all pixel colors to 'off' } void loop() { // pixels.Color() takes RGB values, from 0,0,0 up to 255,255,255 // Here we're using a dim green color - these things are so bright at max: pixels.setPixelColor(0, pixels.Color(0, 50, 50)); pixels.show(); // Send the updated pixel colors to the hardware. delay(DELAYVAL); // Pause before next pass through loop //Let's use a red pixels.setPixelColor(0, pixels.Color(50, 0, 50)); pixels.show(); // Send the updated pixel colors to the hardware. delay(DELAYVAL); // Pause before next pass through loop } ``` Using setbrightness to simplify colours and brightness ```cpp #include <Arduino.h> // NeoPixel Ring simple sketch (c) 2013 Shae Erisson // Released under the GPLv3 license to match the rest of the // Adafruit NeoPixel library #include <Adafruit_NeoPixel.h> // Which pin on the Arduino is connected to the NeoPixels? #define PIN 8 // How many NeoPixels are attached to the Arduino? #define NUMPIXELS 1 // When setting up the NeoPixel library, we tell it how many pixels, // and which pin to use to send signals. Note that for older NeoPixel // strips you might need to change the third parameter -- see the // strandtest example for more information on possible values. Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); #define DELAYVAL 1000 // Time (in milliseconds) to pause. In this case 1s void setup() { pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED) pixels.clear(); // Set all pixel colors to 'off' pixels.setBrightness(20); } void loop() { // pixels.Color() takes RGB values, from 0,0,0 up to 255,255,255 // Here we're using a dim green color - these things are so bright at max: pixels.setPixelColor(0, pixels.Color(0, 255, 255)); pixels.show(); // Send the updated pixel colors to the hardware. delay(DELAYVAL); // Pause before next pass through loop //Let's use a red pixels.setPixelColor(0, pixels.Color(255, 0, 255)); pixels.show(); // Send the updated pixel colors to the hardware. delay(DELAYVAL); // Pause before next pass through loop } ``` ::: :::info #### Extention Exercise Lets cycle though a rainbow of colours. This function from Adafruit might help - it converts a value from 0-255 to a colour of the rainbow. Note it is more explicit about what kind of int we are using, in this case a 32 bit unsigned int (0 → 4 294 967 295) ```cpp // Input a value 0 to 255 to get a color value. // The colours are a transition r - g - b - back to r. uint32_t Wheel(byte WheelPos) { if(WheelPos < 85) { return pixels.Color(WheelPos * 3, 255 - WheelPos * 3, 0); } else if(WheelPos < 170) { WheelPos -= 85; return pixels.Color(255 - WheelPos * 3, 0, WheelPos * 3); } else { WheelPos -= 170; return pixels.Color(0, WheelPos * 3, 255 - WheelPos * 3); } } ``` For now just put functions like this just before your setup function. You can also use forward declarion in C++ to put your functions later. Header files ```.h``` are another way to solve this, but we will leave this for now. :::spoiler Answer Rainbow cycle ```cpp #include <Arduino.h> #include <Adafruit_NeoPixel.h> // Which pin on the Arduino is connected to the NeoPixels? #define PIN 8 // How many NeoPixels are attached to the Arduino? #define NUMPIXELS 1 // When setting up the NeoPixel library, we tell it how many pixels, // and which pin to use to send signals. Note that for older NeoPixel // strips you might need to change the third parameter -- see the // strandtest example for more information on possible values. Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); #define DELAYVAL 20 // Time (in milliseconds) to pause. In this case 1s // Input a value 0 to 255 to get a color value. // The colours are a transition r - g - b - back to r. uint32_t Wheel(byte WheelPos) { if(WheelPos < 85) { return pixels.Color(WheelPos * 3, 255 - WheelPos * 3, 0); } else if(WheelPos < 170) { WheelPos -= 85; return pixels.Color(255 - WheelPos * 3, 0, WheelPos * 3); } else { WheelPos -= 170; return pixels.Color(0, WheelPos * 3, 255 - WheelPos * 3); } } void setup() { pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED) pixels.clear(); // Set all pixel colors to 'off' pixels.setBrightness(50); } void loop() { for(int i; i<=255;i++){ pixels.setPixelColor(0, Wheel(i)); pixels.show(); // Send the updated pixel colors to the hardware. delay(DELAYVAL); // Pause before next pass through loop } } ``` ::: ## Serial The f405 chip on the feather has a native usb port - this can be used ina number of ways, it can emulate a keyboard or mouse (HID mode), mass storage or a serial device. We will use it as a serial device. This is handy way of interacting with your code on the microntroller. It's also the simpliest way to debug your program - print out parameters at various points in your code. Note that there are far more sophisticated methods of debugging this chip - lookup JTAG. Print statements are an easier place to start. Let's print out the ASCII table from our microcontroller. ```cpp #include <Arduino.h> /* ASCII table Prints out byte values in all possible formats: - as raw binary values - as ASCII-encoded decimal, hex, octal, and binary values For more on ASCII, see http://www.asciitable.com and http://en.wikipedia.org/wiki/ASCII The circuit: No external hardware needed. created 2006 by Nicholas Zambetti <http://www.zambetti.com> modified 9 Apr 2012 by Tom Igoe This example code is in the public domain. http://www.arduino.cc/en/Tutorial/ASCIITable */ void setup() { //Initialize serial and wait for port to open: Serial.begin(9600); while (!Serial) { ; // wait for serial port to connect. Needed for native USB port only } // prints title with ending line break Serial.println("ASCII Table ~ Character Map"); } // first visible ASCIIcharacter '!' is number 33: int thisByte = 33; // you can also write ASCII characters in single quotes. // for example, '!' is the same as 33, so you could also use this: // int thisByte = '!'; void loop() { // prints value unaltered, i.e. the raw binary version of the byte. // The Serial Monitor interprets all bytes as ASCII, so 33, the first number, // will show up as '!' Serial.write(thisByte); Serial.print(", dec: "); // prints value as string as an ASCII-encoded decimal (base 10). // Decimal is the default format for Serial.print() and Serial.println(), // so no modifier is needed: Serial.print(thisByte); // But you can declare the modifier for decimal if you want to. // this also works if you uncomment it: // Serial.print(thisByte, DEC); Serial.print(", hex: "); // prints value as string in hexadecimal (base 16): Serial.print(thisByte, HEX); Serial.print(", oct: "); // prints value as string in octal (base 8); Serial.print(thisByte, OCT); Serial.print(", bin: "); // prints value as string in binary (base 2) also prints ending line break: Serial.println(thisByte, BIN); // if printed last visible character '~' or 126, stop: if (thisByte == 126) { // you could also use if (thisByte == '~') { //restart thisByte = 33; delay(5000); Serial.print("\n \n \n \n"); //print some empty lines Serial.println("ASCII Table ~ Character Map"); } // go on to the next character thisByte++; } ``` Upload this code to the microcontroller then click the serial console button on the platformIO bottom bar. It looks like a tiny plug icon on the same bar you use to upload code. #### In Linux and MacOS If you don't want to use the built in serial console you can also open a linux terminal and use minicom or picocom to connect to the serial port, it'll probably be something like ```/dev/ttyACM0``` for picocom ``` bash picocom -b 9600 /dev/ttyACM0 ``` To exit picocom hold control a and press q #### In windows You can use putty or a similar program to connect to the serial port, eg COM8 you might have to try a few different COM numbers until it shows up ## Serial Input There are many ways to readin serial data. We will use ```parseInt``` and serial read ```Serial.read()``` These command read one character from the serial buffer on the microcontroller. As they read or parseint they will remove the first character in the buffer so a subsequent call can read the next. Look at the arduino docs for more. We also need the ```Serial.available() > 0``` command to let us know if there is data in the serial buffer Set the brightness of the led via serial input ```cpp #include <Arduino.h> #include <Adafruit_NeoPixel.h> // Which pin on the Arduino is connected to the NeoPixels? #define PIN 8 // How many NeoPixels are attached to the Arduino? #define NUMPIXELS 1 // When setting up the NeoPixel library, we tell it how many pixels, // and which pin to use to send signals. Note that for older NeoPixel // strips you might need to change the third parameter -- see the // strandtest example for more information on possible values. Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); int incomingByte = 0; // for incoming serial data void setup() { pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED) pixels.clear(); // Set all pixel colors to 'off' //Set led colour pixels.setPixelColor(0, pixels.Color(255, 0, 255)); Serial.begin(9600); while (!Serial) { ; // wait for serial port to connect. Needed for native USB port only } Serial.println("ready to get the brightness"); } void loop() { // if there's any serial available, read it: while (Serial.available() > 0) { // look for the next valid integer in the incoming serial stream: int brightness = Serial.parseInt(); // look for the ':' we will use this to indicate the end of data if (Serial.read() == ':') { // print the the brightness in one string Serial.print("Brightness received: "); Serial.print(brightness, DEC); //Set led colour pixels.setBrightness(brightness); pixels.show(); // Send the updated pixel colors to the hardware. } } } ``` :::success #### Exercise Let's set the led colour by sending serial to the F405. Let's use the following format ```RED,GREEN,BLUE:``` :::spoiler Answer ``` #include <Arduino.h> #include <Adafruit_NeoPixel.h> // Which pin on the Arduino is connected to the NeoPixels? #define PIN 8 // How many NeoPixels are attached to the Arduino? #define NUMPIXELS 1 // When setting up the NeoPixel library, we tell it how many pixels, // and which pin to use to send signals. Note that for older NeoPixel // strips you might need to change the third parameter -- see the // strandtest example for more information on possible values. Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); int incomingByte = 0; // for incoming serial data void setup() { pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED) pixels.clear(); // Set all pixel colors to 'off' Serial.begin(9600); while (!Serial) { ; // wait for serial port to connect. Needed for native USB port only } Serial.println("ready to get colours"); } void loop() { // if there's any serial available, read it: while (Serial.available() > 0) { // look for the next valid integer in the incoming serial stream: int red = Serial.parseInt(); // do it again: int green = Serial.parseInt(); // do it again: int blue = Serial.parseInt(); // look for the newline. That's the end of your sentence: if (Serial.read() == ':') { // print the three numbers in one string Serial.print(red, DEC); Serial.print(" "); Serial.print(green, DEC); Serial.print(" "); Serial.println(blue, DEC); //Set led colour pixels.setPixelColor(0, pixels.Color(red, green, blue)); pixels.show(); // Send the updated pixel colors to the hardware. } } } ``` ::: :::info #### Extention Exercise The microcontroller is actually very fast and in the excerise above is probably just sitting idle waiting for the next character to come in, even if we send them all "at once". Lookup how to do this more efficiently. I'd lookup the standard C function ```strtok``` and ```atoi```. Some good thoughts here: https://forum.arduino.cc/index.php?topic=396450 :::spoiler ```cpp #include <Arduino.h> #include <Adafruit_NeoPixel.h> // Which pin on the Arduino is connected to the NeoPixels? #define PIN 8 // How many NeoPixels are attached to the Arduino? #define NUMPIXELS 1 // When setting up the NeoPixel library, we tell it how many pixels, // and which pin to use to send signals. Note that for older NeoPixel // strips you might need to change the third parameter -- see the // strandtest example for more information on possible values. Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); #define DELAYVAL 1000 // Time (in milliseconds) to pause. In this case 1s // Define some parameters for serial input const byte numChars = 32; //max length of allowable input char receivedChars[numChars]; //global recieved characters boolean newData = false; uint32_t colours[] = {0,0,0}; //Some good thoughts on serial input processing in arduino: https://forum.arduino.cc/index.php?topic=396450 void recvWithStartEndMarkers() { static boolean recvInProgress = false; static byte ndx = 0; char startMarker = '<'; char endMarker = '>'; char rc; while (Serial.available() > 0 && newData == false) { rc = Serial.read(); if (recvInProgress == true) { if (rc != endMarker) { receivedChars[ndx] = rc; ndx++; if (ndx >= numChars) { ndx = numChars - 1; } } else { receivedChars[ndx] = '\0'; // terminate the string recvInProgress = false; ndx = 0; newData = true; } } else if (rc == startMarker) { recvInProgress = true; } } } void processNewData() { if (newData == true) { Serial.print("Colours in ... "); Serial.println(receivedChars); newData = false; // split the data into its parts char * strtokIndx; // this is used by strtok() as an index strtokIndx = strtok(receivedChars,","); // get the first part - the string colours[0] = atoi(strtokIndx); // convert this part to an integer strtokIndx = strtok(NULL, ","); // this continues where the previous call left off colours[1] = atoi(strtokIndx); // convert this part to an integer strtokIndx = strtok(NULL, ","); // this continues where the previous call left off colours[2] = atoi(strtokIndx); // convert this part to an integer pixels.setPixelColor(0, pixels.Color(colours[0], colours[1], colours[2])); pixels.show(); // Send the updated pixel colors to the hardware. } } void setup() { pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED) pixels.clear(); // Set all pixel colors to 'off' Serial.begin(115200); while (!Serial) { ; // wait for serial port to connect. Needed for native USB port only } Serial.println("ready to get colours"); } void loop() { recvWithStartEndMarkers(); processNewData(); } ``` ::: ### Looking closer at using serial port Your program must call the **Serial.begin()** function before it can use serial input or output. This function initialises serial communication, and takes a single parameter: the desired communication speed, or baud rate, and is the number of bits sent per second. You must use the same speed for the sending side and the receiving side, or you will see nonesense (or nothing at all) on the screen. The **Serial.println** function then writes the value of to the serial port. When println is used, it shows that a new line should be added after the value is printed. You can display text using the **Serial.print()** function, which is similar to **printf()** function in C programming. **Serial.println** and **Serial.print()** functions are sending data in ASCII. If you want to send data such as sensor data in a byte or series of bytes, you can use **Serial.write()**. ## Interrupts The microcontroller has a way to stop code that is currently running and do something else. This is considered "hard realtime" and generally happens far more promptly than would occur in a computer with an operating system. The f405 has several timers you can use for a bunch of purposes. Here we use TIM1 to fire off a call back function at 10hz, blinking an led with no need for anything in the main loop. ```cpp #include <Arduino.h> //From https://www.visualmicro.com/page/Timer-Interrupts-Explained.aspx volatile byte state = LOW; //we set this as volatitle to indicate that it may be changed inside and interrupt void Update_IT_callback(void) { // Toggle pin. 10hz toogle --> 5Hz PWM state = !state; digitalWrite(LED_BUILTIN, state); } void setup() { TIM_TypeDef *Instance = TIM1; // Instantiate HardwareTimer object. Thanks to 'new' instanciation, HardwareTimer is not destructed when setup() function is finished. HardwareTimer *MyTim = new HardwareTimer(Instance); // configure LED_BUILTIN in output mode pinMode(LED_BUILTIN, OUTPUT); MyTim->setOverflow(10, HERTZ_FORMAT); // 10 Hz MyTim->attachInterrupt(Update_IT_callback); MyTim->resume(); } void loop() { /* Nothing to do all is done by hardware. Even no interrupt required. */ } ``` :::success #### Exercise Lookup interrupt pins and try change the example above to toggle the led when a pin is shorted to ground. A good place to start is the arduino attachinterrupt documentation. :::spoiler ```cpp #include <Arduino.h> //Adapted From https://www.visualmicro.com/page/Timer-Interrupts-Explained.aspx const byte interruptPin = 5; void Update_IT_callback(void) { // Toggle pin. 10hz toogle --> 5Hz PWM digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); } void setup() { // configure pin in output mode pinMode(LED_BUILTIN, OUTPUT); //pull up the pin we will interrupt pinMode(interruptPin, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(interruptPin), Update_IT_callback, FALLING); } void loop() { /* Nothing to do all is done by hardware. Even no interrupt required. */ } ``` :::