my_blog/templates/blog/posts/pi_pico_first_impressions.html

213 lines
6.3 KiB
HTML

{% extends "base.html" %}
{% import "macros.html" as macros %}
{% block page_content %}
<main id="page-content">
<aside id="skip-links">
<nav>
<h3>Skip Links</h3>
<ul class="link-list">
<li><a href="#article-header">skip to "Pi Pico First Impressions"</a></li>
<li><a href="#language-support">skip to "Language Support"</a></li>
<li><a href="#real-applications">skip to "Real Applications"</a></li>
</ul>
</nav>
</aside>
<div id="main-content">
<header id="article-header" aria-label="Pi Pico First Impressions" tabindex="0">
<h2>Pi Pico First Impressions</h2>
<p>Specs? Who need those. I wont go deep into the specs because that would be a waist of our time. You can look them up <a href="">somewhere else</a>.</p>
<h3>What is this dual core ARM M0+ microprocessor good for?</h3>
<p></p>
<h3>What shouldn't you use it for?</h3>
<p>This isn't a linux computer like the other Raspberry Pis so don't bother trying to host a server on it or use it to emulate your favorite retro device. Though you certaintly can if you <a href="">try</a>.</p>
<p>It doesn't have wireless connectivity built into it like the esp devices so you have to bring your own at which point you might consider an integrated solution.</p>
</header>
<section id="language-support" aria-label="Language Support" tabindex="0">
<h3>Language Support</h3>
<p>The Raspberry Pi foundation supports two languages on the Pi Pico. C and their port of MicroPython to the board.</p>
<p></p>
<table>
<summary>Table summary</summary>
<thead>
<th>Language</th>
<th>Backer</th>
<th>Recommended IDE</th>
<th>Documentation</th>
</thead>
<tr>
<td>C</td>
<td>Raspberry Pi Foundation</td>
<td>Visual Studio Code</td>
<td>
<ul>
<li>PDF</li>
<li>Website</li>
</ul>
</td>
</tr>
<tr>
<td>MicroPython</td>
<td>Raspberry Pi Foundation</td>
<td>Thonny</td>
<td>
<ul>
<li>PDF</li>
<li>MicroPython Website</li>
</ul>
</td>
</tr>
<tr>
<td>CircuitPython</td>
<td>Adafruit</td>
<td>MuPython</td>
<td>
<ul>
<li>Website</li>
</ul>
</td>
</tr>
<tr>
<td>Arduino C</td>
<td>Arduino</td>
<td>Arduino IDE</td>
<td>
<ul>
<li>Website</li>
</ul>
</td>
</tr>
</table>
</section>
<section id="real-applications" aria-label="Real Applications" tabindex="0">
<h3>Real Applications</h3>
<h4>C++ and MicroPython Support</h4>
<p>To test the language support I created the same program in both MicroPython and C++ using the C SDK. In each program I wrote a driver for the <a href="">MPU-6050</a> a sensor with 6 degrees of freedom, and used it to control 2 servos in order to level them.</p>
<figure>
<img src=""
title="Test Program Setup"
alt="A Pi Pico on a bread board connected to an MPU-6050 and two servos via jumper wires.">
<figcaption>The MPU-6050 is connected to one of the Pico's i2c busses while the servos are connected to PWM pins.</figcaption>
</figure>
<h4>Programmable IO (PIO)</h4>
<p>To test the PIO feature of the board I wrote two programs using the C SDK. Each of them poll a <a href="">key matrix</a> similar to what you would find on a USB keyboard. The first program does it by setting GPIO pins using one of the main cores of the microcontroller while the other polls the keys using the programmable IO state machines.</p>
<figure>
<img src=""
title="Keyboard Matrix Wiring Diagram"
alt="A wiring diagram for a 3 by 3 keyboard matrix.">
<figcaption>Each row is connected to each column by a diode and a button in parrallel. The diodes are oriented so that current flows from the rows to the columns.</figcaption>
</figure>
<p>Lets first take a look at the C++ code.</p>
<code>
<pre>
template<uint8_t row_count, uint8_t col_count>
class Keyboard {
public:
// ... snip ...
void poll_buttons() {
uint8_t key_index = 0;
for (uint8_t col = 0, col_pin = _first_col_pin; col < col_count; col++, col_pin++) {
gpio_put(col_pin, 0);
for (uint8_t row = 0; row < row_count; row++) {
const uint8_t row_pin = _first_row_pin + row;
const bool previous_state{_keys_pressed[key_index]};
const bool is_down{gpio_get(row_pin) == 0};
_keys_pressed[key_index] = is_down;
if (is_down != previous_state) {
const auto event_type = static_cast<KeyEventE>(KeyEventE::KEY_UP - static_cast<int>(is_down));
_key_events[_key_event_count] = KeyEvent {event_type, key_index};
_key_event_count++;
}
key_index++;
}
gpio_put(col_pin, 1);
}
}
private:
std::array<bool, row_count * col_count> _keys_pressed{};
std::array<KeyEvent, row_count * col_count> _key_events{};
</pre>
</code>
<p>Before we can look at the PIO code we first need to review how exactly the Pico's PIO works.</p>
<code>
<pre style="tab-size: 2;">
.program keyboard
.define PUBLIC ROW_COUNT 3
.define PUBLIC COL_COUNT 3
.define COL_0_LOW 0b11110
.define COL_1_LOW 0b11101
.define COL_2_LOW 0b11011
; Assume all switches are open.
; Initialize scratch register X(previous state) to be filled with ones.
; Ones indicate open switches.
start:
set X, 0
mov X, ~X
jmp poll
key_changed:
; copy current state(scratch register Y) into previous state(scratch register X)
mov X, Y
; Write the contents of the input shift register(ISR) to the RX FIFO,
; also clears the ISR.
push
.wrap_target
poll:
; clear the input shift register.
; It will be filled with garbage if we didn't push.
mov ISR, NULL
; set column 0 to low all others to high
; what 31 cycles to allow the signal to stabilize
set PINS, COL_0_LOW [31]
; wait another 31 cycles to continue to allow the signal to stabilize
nop [31]
; read column 0 to the input shift register(ISR)
in PINS, ROW_COUNT
set PINS, COL_1_LOW [31]
nop [31]
in PINS, ROW_COUNT
set PINS, COL_2_LOW [31]
nop [31]
in PINS, ROW_COUNT
; copy ISR into scratch register Y
; flip the bits while copying because the signal is active low
mov Y, ~ISR
; compare current state Y to previous state X
; if state changed goto key_changed
jmp X != Y, key_changed
; keys didn't change so poll again
.wrap
</pre>
</code>
</section>
</div>
</main>
{% endblock page_content %}