From ab7af4df18a355e1627f3394231c8a31494dba08 Mon Sep 17 00:00:00 2001 From: Adin Ackerman Date: Mon, 12 Aug 2024 11:57:29 -0700 Subject: [PATCH] ... --- content/assignments/dev-board/_index.md | 4 +- content/assignments/dev-board/assembly.md | 4 +- content/assignments/full-stack/BLE/_index.md | 7 + content/assignments/full-stack/USB/_index.md | 53 +++ .../full-stack/{tutorial.md => USB/client.md} | 329 +----------------- .../assignments/full-stack/USB/firmware.md | 236 +++++++++++++ .../full-stack/USB/what-just-happened.md | 19 + content/assignments/full-stack/_index.md | 42 ++- content/assignments/light-shield/_index.md | 5 +- .../spinning-and-blinking/arduino/spinning.md | 10 + .../spinning-and-blinking/rust/spinning.md | 2 +- content/assignments/vu-meter/firmware.md | 26 +- 12 files changed, 390 insertions(+), 347 deletions(-) create mode 100644 content/assignments/full-stack/BLE/_index.md create mode 100644 content/assignments/full-stack/USB/_index.md rename content/assignments/full-stack/{tutorial.md => USB/client.md} (53%) create mode 100644 content/assignments/full-stack/USB/firmware.md create mode 100644 content/assignments/full-stack/USB/what-just-happened.md create mode 100644 content/assignments/spinning-and-blinking/arduino/spinning.md diff --git a/content/assignments/dev-board/_index.md b/content/assignments/dev-board/_index.md index 3cd7bef..59b7477 100644 --- a/content/assignments/dev-board/_index.md +++ b/content/assignments/dev-board/_index.md @@ -6,10 +6,10 @@ next: assignments/dev-board/assembly weight: 2 --- -For this assignment you will be assembling an **EnVision DevBoard**. +For this assignment you will be assembling an **EnVision Mini DevBoard**. This assignment is the next piece to making your own VUMeter. The DevBoard contains the microcontroller that will control the light shield. -The DevBoard is _not_ as simple as the previous, and will require additional equipment. This time, you will use a **stencil** to apply **solder paste** _exactly_ on each pad. +The DevBoard is *not* as simple as the previous, and will require additional equipment. This time, you will use a **stencil** to apply **solder paste** _exactly_ on each pad. Hope you don't have shaky hands! diff --git a/content/assignments/dev-board/assembly.md b/content/assignments/dev-board/assembly.md index b316329..53fb70b 100644 --- a/content/assignments/dev-board/assembly.md +++ b/content/assignments/dev-board/assembly.md @@ -61,7 +61,7 @@ Now we will start placing our components. As you work, you can request the components you need from the TAs at the component table. -To find out what you need, refer to the **B**ill **O**f **M**aterials [here](https://github.com/ECE-196/DevBoard/blob/main/BOM.xlsx). +To find out what you need, refer to the BOM[^1] [here](https://github.com/ECE-196/DevBoard/blob/main/BOM.xlsx). Once you have a component from the B.O.M. you can see which PCB labels the component corresponds to in the _designator_ column. With tweezers, carefully place each component on to the labeled position on the PCB. Make sure that the components you place are centered on the pads, and be careful not @@ -122,3 +122,5 @@ Place the connector back down, remove the heat gun, and look again at your pins - If your solder paste didn't turn out clean, it is much easier to just repaste. Don't try to make it work if you know you can do better. - Double check the BOM as you place components, while you can take components off of the paste if, it can easily cause bridging. - Take your time on every step, this is a very delicate process. + +[^1]: A **B**ill **O**f **M**aterials (BOM) is a document outlining the required components quantities and placements for a board. diff --git a/content/assignments/full-stack/BLE/_index.md b/content/assignments/full-stack/BLE/_index.md new file mode 100644 index 0000000..a9f544d --- /dev/null +++ b/content/assignments/full-stack/BLE/_index.md @@ -0,0 +1,7 @@ +--- +title: BLE +type: docs +prev: assignments/full-stack/ +next: assignments/full-stack/ble/tutorial +weight: 2 +--- diff --git a/content/assignments/full-stack/USB/_index.md b/content/assignments/full-stack/USB/_index.md new file mode 100644 index 0000000..cd92ad5 --- /dev/null +++ b/content/assignments/full-stack/USB/_index.md @@ -0,0 +1,53 @@ +--- +title: USB +type: docs +prev: assignments/full-stack/ +next: assignments/full-stack/usb/firmware +weight: 1 +--- + +Let's take a look at the hierarchy of the system we are about to design: + +```mermaid +graph LR + subgraph "DevBoard" + subgraph "Front End" + A2(LED) + end + + subgraph "Back End" + B2(Serial) + C2(Callbacks) + D2(Logic) + end + + B2 --> C2 --> D2 --> A2 + D2 --> B2 + end + + subgraph "Computer (Python)" + subgraph "Front End" + A1(UI) + B1(Alerts) + end + + subgraph "Back End" + C1(Callbacks) + D1(Logic) + E1(Serial) + end + + A1 --> C1 --> D1 <--> E1 + D1 --> B1 + end + + B2 <--> E1 +``` + +Now, I know this looks complicated, but we will tackle each block one by one, nice and slow. + +Once you are done with this, you will have a solid understanding of creating systems involving +bidirectional communication between 2 devices, which is *super* useful for *a ton* of +applications (including your final project). + +So let's get started. diff --git a/content/assignments/full-stack/tutorial.md b/content/assignments/full-stack/USB/client.md similarity index 53% rename from content/assignments/full-stack/tutorial.md rename to content/assignments/full-stack/USB/client.md index b697d17..0d2c91e 100644 --- a/content/assignments/full-stack/tutorial.md +++ b/content/assignments/full-stack/USB/client.md @@ -1,310 +1,10 @@ --- -title: Tutorial +title: Client type: docs -prev: assignments/full-stack/ -weight: 1 +prev: assignments/full-stack/usb/firmware +weight: 2 --- -Let's take a look at the hierarchy of the system we are about to design: - -```mermaid -graph LR - subgraph "DevBoard" - subgraph "Front End" - A2(LED) - end - - subgraph "Back End" - B2(Serial) - C2(Callbacks) - D2(Logic) - end - - B2 --> C2 --> D2 --> A2 - D2 --> B2 - end - - subgraph "Computer (Python)" - subgraph "Front End" - A1(UI) - B1(Alerts) - end - - subgraph "Back End" - C1(Callbacks) - D1(Logic) - E1(Serial) - end - - A1 --> C1 --> D1 <--> E1 - D1 --> B1 - end - - B2 <--> E1 -``` - -Now, I know this looks complicated, but we will tackle each block one by one, nice and slow. - -Once you are done with this, you will have a solid understanding of creating systems involving bidirectional communication between 2 devices, which is _super_ useful for _a ton_ of applications (including your final project). - -So let's get started. - -## Driving an LED - -We'll start simple, and just make a user controllable LED blink once per second. Before you begin, make sure that your Board is configured to the ESP32S3 Dev Module. - -On the DevBoard, the pin of the LED we will use is `17` (LED1). - -Here is the code: - -```cpp -const int LED{17}; - -void setup() { - pinMode(LED, OUTPUT); -} - -void loop() { - digitalWrite(LED, HIGH); - delay(1000); - digitalWrite(LED, LOW); - delay(1000); -} -``` - -The `setup` function runs once on boot. - -The `loop` function runs over and over again forever. - -## Hello, World! - -Now let's print some messages over the USB connection. - -```c -void setup() { - USBSerial.begin(9600); -} - -void loop() { - USBSerial.println("Hello, World!"); - delay(1000); -} -``` - -This prints `Hello, World!` every second. But how can we see it? - -If you are using the Arduino IDE, you can open the serial monitor, set the [baudrate](https://www.setra.com/blog/what-is-baud-rate-and-what-cable-length-is-required-1) to `9600`, and watch the hello's flow in! - -Another way we can read these messages is with Python! - -Python has a library called `pyserial`. - -To install it in your active Python environment, simply run: - -``` -python -m pip install pyserial -``` - -...in your terminal. - -{{< callout type="info" >}} - You can use Arduino IDE to determine the name of the port your DevBoard is on. -{{< /callout >}} - -You can now open a Python file or REPL and write/run the following code: - -```python -from serial import Serial, SerialException - -with Serial('/your/port', 9600) as ser: - while True: - print(ser.readline().decode()) -``` - -`.readline()` accumulates bytes until the newline (`\n` ) byte is received. - -We use `.decode()` because `.readline()` returns `bytes` which can be _decoded_ into a string. - -## Serial LED - -Ok, so we can blink an LED, and we can send bytes from the DevBoard to our computer, but what about the other way 'round? - -In order to control the LED from our computer, we need to send messages the other way. - -To do this, we first set up _receiving_ bytes over serial on the DevBoard: - -### Interrupts - -An _interrupt_ is an event driven signal that runs code. - -In our case, an event we care to _handle_ is if we receive a byte over serial. - -Luckily, this event is available to us, it's called `ARDUINO_HW_CDC_RX_EVENT`. - -Wow, what it's trying to say is that if the Serial port's _receive buffer_ is not empty, this event will be triggered. - -So let's define a function we want to be called when that event is triggered (we receive a byte): - -```c -void on_receive(void* event_handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { ... } -``` - -> The arguments of this function are defined by the type `esp_event_handler_t`. You can refer to Espressif's [documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/esp_event.html) to see more. - -Then, we register the interrupt with the `USBSerial` peripheral in our `setup()` like so: - -```c -void setup() { - pinMode(LED, OUTPUT); - - // register "on_receive" as callback for RX event - USBSerial.onEvent(ARDUINO_HW_CDC_RX_EVENT, on_receive); - USBSerial.begin(9600); -} -``` - -Ok, we also still configure the LED to be an output, great. - -Oh, and we correspond the byte received event to our function, nice! - -### Serial - -So, what should be in our `on_receive` function? - -Well, the first thing we need to do is get the data from the Serial port's buffer: - -```c -// read one byte -int state = USBSerial.read(); -``` - -We consider each byte received to be the target LED state (_sent by the computer_). - -Then we need to do some validation, we know the LED can only be set to `LOW`, or `HIGH`, so we need to check the received byte is equal to either of those: - -```c -// guard byte is valid LED state -if (!(state == LOW || state == HIGH)) { - // invalid byte received - // what else should we do? - return; -} -``` - -If we find the byte to be valid, we proceed to updating the LED: - -```c -// update LED with valid state -digitalWrite(LED, state); -``` - -Ok, this is pretty good, let's hop back over to Python. - -Let's try sending the byte `0x1` and see what happens: - -```python -with Serial('/your/port', 9600) as ser: - ser.write(bytes([0x1])) - input() # keep port open to see the LED turn on -``` - -The LED should turn on! - -Ok! This is cool! But... - -### Validation - -What if we send an invalid byte? How could the app know? It _should_ know, right? - -Validation is an important consideration when developing communication systems. So let's add it. - -Let's create two more constants at the top of our file: - -```c -const int LED{17}; - -// add these -const int S_OK{0xaa}; -const int S_ERR{0xff}; -``` - -We can send back one of these depending on the validity of the received data. - -Let's go back and update `on_receive`: - -```c -void on_receive(void* event_handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { - // read one byte - int state = USBSerial.read(); - - // guard byte is valid LED state - if (!(state == LOW || state == HIGH)) { - // invalid byte received - // report error - USBSerial.write(S_ERR); - return; - } - - // update LED with valid state - digitalWrite(LED, state); - USBSerial.write(S_OK); -} -``` - -Now whenever the app sends an LED state, it should expect a confirmation response. - -You can try this in Python: - -```python -with Serial('/your/port', 9600) as ser: - ser.write(bytes([0x1])) - print(ser.read() == bytes([0xaa])) - - ser.write(bytes([0x0])) - print(ser.read() == bytes([0xaa])) - - ser.write(bytes([0x2])) - print(ser.read() == bytes([0xff])) -``` - -You should see 3 `True`'s. - -### Loop? - -What happened to `loop()`? What do we need to put in there? - -Well... - -```c -void loop() { } -``` - -Nothing! - -Our code is completely interrupt driven, so the `loop` function need not be populated :\) - -At this point, we have completed half of the system! - -```mermaid -graph LR - subgraph "DevBoard" - subgraph "Front End" - A2(LED) - end - - subgraph "Back End" - B2(Serial) - C2(Callbacks) - D2(Logic) - end - - B2 --> C2 --> D2 --> A2 - D2 --> B2 - end -``` - -## App - Time for the other half... This is going to be a lot, not gonna lie this is going to go pretty deep. @@ -319,7 +19,7 @@ This may seem trivial at first, but you must realize that Python - by default - This is bad, we don't like this, so we will need to take care to design our app with _concurrency_ in mind. -### UI +## UI Let's start easy and just set up a simple UI. @@ -365,7 +65,7 @@ We have: - a button to test sending an invalid byte - a disconnect button -### Backend +## Backend We now need to implement the missing backend components. @@ -536,7 +236,7 @@ def send_invalid(self): And now these will properly handle an `S_ERR` response. -### Safe Resource Acquisition +## Safe Resource Acquisition Another thing we need to do is make sure our serial port is properly closed when our app exits. @@ -562,7 +262,7 @@ if __name__ == '__main__': app.mainloop() ``` -### Threading +## Threading Right now, if any serial code gets stuck or just takes a long time, our UI will freeze for that time. @@ -620,18 +320,3 @@ Our custom type inherits from `Serial` and overrides the member functions we use Effectively, our type behaves _exactly like the `Serial` type_ but with a lock around every function call. Now replace every use of the `Serial` type with `LockedSerial`. - -## What Just Happened - -Ok! That was a lot! But i'm glad you made it :\) - -You now know how to: - -- write interrupt driven firmware -- use the serial peripheral -- digital communication between two devices - - validate data -- create user interfaces with Python - - interaction between front and back end -- threading - - locks diff --git a/content/assignments/full-stack/USB/firmware.md b/content/assignments/full-stack/USB/firmware.md new file mode 100644 index 0000000..b248878 --- /dev/null +++ b/content/assignments/full-stack/USB/firmware.md @@ -0,0 +1,236 @@ +--- +title: Firmware +type: docs +prev: assignments/full-stack/usb +next: assignments/full-stack/usb/client +weight: 1 +--- + +## Hello, World! + +Let's print some messages over the USB connection. + +```cpp +void setup() { + USBSerial.begin(9600); +} + +void loop() { + USBSerial.println("Hello, World!"); + delay(1000); +} +``` + +This prints `Hello, World!` every second. But how can we see it? + +If you are using the Arduino IDE, you can open the serial monitor, set the baudrate[^1] to `9600`, and watch the hello's flow in! + +[^1]: The *baudrate* is the rate at which the signal on the wire can change in "baud's" per second. + +Another way we can read these messages is with Python! + +Python has a library called `pyserial`. + +To install it in your active Python environment, simply run: + +``` +python -m pip install pyserial +``` + +...in your terminal. + +{{< callout type="info" >}} + You can run `python -m serial` to determine the name of the port your DevBoard is on. +{{< /callout >}} + +You can now open a Python file or REPL and write/run the following code: + +```python +from serial import Serial, SerialException + +with Serial('/your/port', 9600) as ser: + while True: + print(ser.readline().decode()) +``` + +`.readline()` accumulates bytes until the newline (`\n` ) byte is received. + +We use `.decode()` because `.readline()` returns `bytes` which can be _decoded_ into a string. + +## Serial LED + +Ok so we can send bytes from the DevBoard to our computer, but what about the other way 'round? + +Let's try to control an LED from our computer. To do this, we need to send messages the other way. + +We first set up *receiving* bytes over serial on the DevBoard: + +### Interrupts + +An *interrupt* is an event driven signal that runs code. + +In our case, an event we care to *handle* is if we receive a byte over serial. + +Luckily, this event is available to us, it's called `ARDUINO_HW_CDC_RX_EVENT`. + +Wow, what it's trying to say is that if the serial port's *receive buffer* is not empty, this event will be triggered. + +So let's define a function we want to be called when that event is triggered (we receive a byte): + +```cpp +void on_receive(void* event_handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { ... } +``` + +> The signature of this function is defined by the type `esp_event_handler_t`. You can refer to Espressif's [documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/esp_event.html) to see more. + +Then, we register the interrupt with the `USBSerial` peripheral in our `setup()` like so: + +```cpp +void setup() { + pinMode(LED, OUTPUT); + + // register "on_receive" as callback for RX event + USBSerial.onEvent(ARDUINO_HW_CDC_RX_EVENT, on_receive); + USBSerial.begin(9600); +} +``` + +Ok, we also configure an LED to be an output, great. + +Oh, and we correspond the byte received event to our function, nice! + +### Serial + +So, what should be in our `on_receive` function? + +Well, the first thing we need to do is get the data from the serial port's buffer: + +```cpp +// read one byte +char state { USBSerial.read() }; +``` + +We consider each byte received to be the target LED state (*sent by the computer*). + +Then we need to do some validation, we know the LED can only be set to `LOW`, or `HIGH`, so we need to check the received byte is equal to either of those: + +```cpp +// guard byte is valid LED state +if (!(state == LOW || state == HIGH)) { + // invalid byte received + // what else should we do? + return; +} +``` + +If we find the byte to be valid, we proceed to updating the LED: + +```cpp +// update LED with valid state +digitalWrite(LED, state); +``` + +Ok, this is pretty good, let's hop back over to Python. + +Let's try sending the byte `0x1` and see what happens: + +```python +with Serial('/your/port', 9600) as ser: + ser.write(bytes([0x1])) + input() # keep port open to see the LED turn on +``` + +The LED should turn on! + +Ok! This is cool! But... + +### Validation + +What if we send an invalid byte? How could the app know? It *should* know, right? + +Validation is an important consideration when developing communication systems. So let's add it. + +Let's create two more constants at the top of our file: + +```cpp +const int LED { 17 }; + +// add these +const char S_OK { 0xaa }; +const char S_ERR { 0xff }; +``` + +We can send back one of these depending on the validity of the received data. + +Let's go back and update `on_receive`: + +```cpp +void on_receive(void* event_handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { + // read one byte + char state { USBSerial.read() }; + + // guard byte is valid LED state + if (!(state == LOW || state == HIGH)) { + // invalid byte received + // report error + USBSerial.write(S_ERR); + return; + } + + // update LED with valid state + digitalWrite(LED, state); + USBSerial.write(S_OK); +} +``` + +Now whenever the app sends an LED state, it should expect a confirmation response. + +You can try this in Python: + +```python +with Serial('/your/port', 9600) as ser: + ser.write(bytes([0x1])) + assert ser.read() == bytes([0xaa]) + + ser.write(bytes([0x0])) + assert ser.read() == bytes([0xaa]) + + ser.write(bytes([0x2])) + assert ser.read() == bytes([0xff]) +``` + +If an error is raised, one of these assertions failed! + +### Loop? + +What happened to `loop()`? What do we need to put in there? + +Well... + +```cpp +void loop() { } +``` + +Nothing! + +Our code is completely interrupt driven, so the `loop` function need not be populated :) + +At this point, we have completed half of the system! + +```mermaid +graph LR + subgraph "DevBoard" + subgraph "Front End" + A2(LED) + end + + subgraph "Back End" + B2(Serial) + C2(Callbacks) + D2(Logic) + end + + B2 --> C2 --> D2 --> A2 + D2 --> B2 + end +``` diff --git a/content/assignments/full-stack/USB/what-just-happened.md b/content/assignments/full-stack/USB/what-just-happened.md new file mode 100644 index 0000000..6026201 --- /dev/null +++ b/content/assignments/full-stack/USB/what-just-happened.md @@ -0,0 +1,19 @@ +--- +title: What Just Happened +type: docs +prev: assignments/full-stack/usb/client +weight: 3 +--- + +Ok! That was a lot! But i'm glad you made it :\) + +You now know how to: + +- write interrupt driven firmware +- use the serial peripheral +- digital communication between two devices + - validate data +- create user interfaces with Python + - interaction between front and back end +- threading + - locks diff --git a/content/assignments/full-stack/_index.md b/content/assignments/full-stack/_index.md index ebc8861..d465151 100644 --- a/content/assignments/full-stack/_index.md +++ b/content/assignments/full-stack/_index.md @@ -30,17 +30,45 @@ You will create a **client** (the GUI running on your computer/phone) which comm **You are once again faced with an important decision** -You now have **four** pathways to choose from: +You have **two*** pathways to choose from: (kind of four pathways) {{< cards >}} - {{< card link="python" title="USB: Python & Arduino" >}} - {{< card link="python" title="USB: Python & Rust" >}} - {{< card link="python" title="BLE: Swift & Arduino" >}} - {{< card link="python" title="BLE: Swift & Rust" >}} + {{< card link="usb" title="USB: Python & Arduino or Rust" >}} + {{< card link="ble" title="BLE: Swift & Arduino or Rust" >}} {{< /cards >}} {{< callout type="warning" >}} - You **must** have a Mac and an iPhone to develop Swift apps. + You **must** have a Mac and an iPhone to use Swift for this assignment. {{< /callout >}} -Similarly to the previous assignment, some of these paths are easier than others, but less interesting. +{{< callout type="warning" >}} + Only use Rust if you completed the Rust path from [Spinning and Blinking]({{< ref "/assignments/spinning-and-blinking/rust" >}}). +{{< /callout >}} + +## Your Options +### USB + +The first two options will teach you how to conduct serial communication over USB[^1]. +On your computer you will use **Python** to create the client. + +You have probably heard of Python before, as it is hugely popular. It's also very easy to learn. + +### BLE + +The last two options will teach you how to communicate with BLE[^2]. You will develop an app +for your phone using **Swift** and **SwiftUI**. + +Swift is a programming language made by Apple[^3] primarily for app development. SwiftUI is +the framework Apple provides for declaratively designing modern, responsive, and frankly +beautiful user interfaces across the Apple ecosystem. + +[^1]: **U**niversal **S**erial **B**us (USB). The classic ports on your computer, phone, and the DevBoard. +[^2]: **B**luetooth **L**ow **E**nergy (BLE). The most modern "style" of Bluetooth communication. +[^3]: Chris Latner was an employee at Apple when he created Swift. He received a lot of push back, +and in fact, had to keep it mostly a secret until he had enough notoriety at the company to +convince his higher ups to devote resources to it. +He also created LLVM, the world's most advanced compiler backend, which Rust (and naturally Swift) **relies on** to provide many of it's +features. This one man has improved the lives of tens, if not hundreds of millions of people simply +by following his passion for engineering and design, despite the adversity he faced. +He has ushered in the next chapter of global technological advancement. It would be wise +to read about his life, you could very quickly become a better engineer! diff --git a/content/assignments/light-shield/_index.md b/content/assignments/light-shield/_index.md index 8f5b459..afb8f3d 100644 --- a/content/assignments/light-shield/_index.md +++ b/content/assignments/light-shield/_index.md @@ -12,6 +12,9 @@ This assignment is the first piece to making your own VUMeter. Over the course o ![](images/in-action.png) -To complete the light shield, you will learn about assembling PCBs with **S**urface **M**ounte**D** components by hand. +To complete the light shield, you will learn about assembling PCBs with SMD[^1] components by hand. Good luck, and don't be afraid to ask for help. + +[^1]: **S**urface **M**ounted **D**evices (SMD) are components that sit on the surface of a PCB +and are soldered directly to exposed copper. diff --git a/content/assignments/spinning-and-blinking/arduino/spinning.md b/content/assignments/spinning-and-blinking/arduino/spinning.md new file mode 100644 index 0000000..32f51dc --- /dev/null +++ b/content/assignments/spinning-and-blinking/arduino/spinning.md @@ -0,0 +1,10 @@ +--- +title: Spinning +type: docs +prev: assignments/spinning-and-blinking/arduino/blinking +weight: 3 +--- + +It's time to get our hands dirty and really change this firmware. We're going to make a motor spin, but to do that, firmware won't be enough. + +Pick up a **Motion Shield** and any complementary components/equipment. diff --git a/content/assignments/spinning-and-blinking/rust/spinning.md b/content/assignments/spinning-and-blinking/rust/spinning.md index 5953615..f2caba4 100644 --- a/content/assignments/spinning-and-blinking/rust/spinning.md +++ b/content/assignments/spinning-and-blinking/rust/spinning.md @@ -1,7 +1,7 @@ --- title: Spinning type: docs -prev: assignments/spinning-and-blinking/blinking +prev: assignments/spinning-and-blinking/rust/blinking weight: 3 --- diff --git a/content/assignments/vu-meter/firmware.md b/content/assignments/vu-meter/firmware.md index 2fb7382..23623f4 100644 --- a/content/assignments/vu-meter/firmware.md +++ b/content/assignments/vu-meter/firmware.md @@ -45,19 +45,19 @@ The first step is to download [this](https://github.com/ECE-196/VUMeter/blob/mai Navigate to [this](https://circuitpython.org/board/espressif_esp32s3_devkitc_1_n8) page. -Click "_Open Installer_"... +Click "*Open Installer*"... ![](images/open-installer.png) -and then click "_Install Bootloader Only_". +and then click "*Install Bootloader Only*". ![](images/installer-select.png) -Click "_Next_" until you reach this screen: +Click "*Next*" until you reach this screen: ![](images/connect-button.png) -Click "_Connect_". This dialog should appear: +Click "*Connect*". This dialog should appear: {{< callout type="info" >}} You may need to grant your browser permission to access your USB ports. @@ -65,9 +65,9 @@ Click "_Connect_". This dialog should appear: ![](images/connect-dialog.png) -Click "_Connect_". +Click "*Connect*". -Click "_Continue_" and wait for the bootloader to flash... +Click "*Continue*" and wait for the bootloader to flash... ![](images/flashing.png) @@ -96,7 +96,7 @@ When the transfer is complete, it will disconnect, and a new drive will appear: ![](images/circuitpy.png) {{< callout type="info" >}} - If a keyboard dialog appears, click "_Quit_" + If a keyboard dialog appears, click "*Quit*" {{< /callout >}} ### Setup Workspace @@ -105,31 +105,31 @@ Now that CircuitPython has been installed on your DevBoard, you can open VSCode ![](images/vscode-open.png) -Click "_Open Folder_" and select the `CIRCUITPY` directory. +Click "*Open Folder*" and select the `CIRCUITPY` directory. The first thing you should do is rename `code.py` to `main.py`. ![](images/vscode-main.png) -_So how do I run this?_ you may ask. +*So how do I run this?* you may ask. Well we first need to tell VSCode how to interact with our CircuitPython runtime. Luckily for us, there is a VSCode extension for this! -Navigate to the extensions pane and search "_python_", install the first result. +Navigate to the extensions pane and search "*python*", install the first result. -Then search "_circuitpython_" -- there should only be one result -- and click install. +Then search "*circuitpython*" -- there should only be one result -- and click install. ![](images/vsscode-ext-install.png) Then go back to the explorer pane and select `main.py`. -In the bottom right, click "_\_", then search for the `ESP32-S3-DevKitC-1-N8`. +In the bottom right, click "*\*", then search for the `ESP32-S3-DevKitC-1-N8`. ![](images/devkit.png) -Then press the little USB icon next to that button, or open the command pallette and search "_open serial_". +Then press the little USB icon next to that button, or open the command pallette and search "*open serial*". Select the appropriate USB port.