Skip to content
Snippets Groups Projects
Commit 38434b0c authored by Jake Read's avatar Jake Read
Browse files

uart pio begins

parent bb2f1fc5
Branches
Tags
No related merge requests found
...@@ -4,3 +4,4 @@ ...@@ -4,3 +4,4 @@
- see even i.e. transfer of some tens-of-megabytes onto an SD card (copying a gcode file) - we observe only ~ 20mb/sec of advertized 80mb/sec or so - see even i.e. transfer of some tens-of-megabytes onto an SD card (copying a gcode file) - we observe only ~ 20mb/sec of advertized 80mb/sec or so
- otherwise, you have notes on what-the-point is in your `scratch` - otherwise, you have notes on what-the-point is in your `scratch`
- and consider linking to the ring-test page - and consider linking to the ring-test page
- and discuss that at the embedded limit, we often run into interrupt-request-handling-time troubles before anything else...
\ No newline at end of file
## 2024 01 03
Today I'd like to check out the RP2040's PIO via the UART example, and see how fast we can sendy UART frames between two devices, as a preliminary speed test.
So - we're wired up, we should hit the scope and then fire up some test code: display (?) uart PIO, blinky, etc ...
The first thing [I'm learning here](https://www.eevblog.com/forum/microcontrollers/8-uarts-using-asm_pio-pio-dma-micropython-on-the-rpi-pico/) and as shown in the [pio rx](https://github.com/raspberrypi/pico-examples/tree/master/pio/uart_rx) and [pio tx](https://github.com/raspberrypi/pico-examples/blob/master/pio/uart_tx/uart_tx.pio) examples is that each state machine can only do one half of a UART... TX or RX, not both as we are accustomed to with a UART peripheral. So, since we are interested in building our little router thing, we actually would only be able to max out at 6 total UARTS there: 2x the-og-peripheral, and 4x PIOs.
The second thing [I'm learning](https://www.instructables.com/Using-RP2040-PIO-in-Arduino-IDE-on-Windows/) is that working with PIO in C is not *that* simple; we write a PIO block `uart_tx.pio` and then use a pio-assembler to write `uart_tx.pio.h` that we can include in our sketch. There is an [online pioasm instance](https://wokwi.com/tools/pioasm). Doing this on windows is a little bit of a pain - and means that we will have two things to call before we can upload code, but not a major-major roadblock.
So, as for reasonable goals for today, I should basically just try to throw-and-catch a block, really simple-like, to test baseline perf.
Well actually, fk it, I will use the online pioasm for the time being...
And we're up with a test, I will find the BAUD limit next, and check if that is affected by changes to f_cpu...
\ No newline at end of file
#include "screen.h"
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Wire.h>
// OLED
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define X_POS 0
#define Y_POS 0
#define TXT_SIZE 1
// even for displays with i.e. "0x78" printed on the back,
// the address that works is 0x3C, IDK
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT);
// warning: is blocking, takes ~ 33ms !
void displayPrint(String msg){
display.clearDisplay();
display.setCursor(X_POS, Y_POS);
display.print(msg);
display.display();
}
void displaySetup(void){
// initialize the screen,
// oddly, SWITCHCAPVCC is the option that works even though OLED is hooked to 5V
display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);
display.clearDisplay();
display.display();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(TXT_SIZE);
display.setTextWrap(true);
display.dim(false);
displayPrint("bonjour...");
}
\ No newline at end of file
#ifndef SCREEN_H_
#define SCREEN_H_
#include <Arduino.h>
void displaySetup(void);
void displayPrint(String msg);
#endif
\ No newline at end of file
#include "screen.h"
#include "uart_tx.pio.h"
// using an RP2040 XIAO
// with earle philhower core
// "D10" - GPIO 3
#define PIN_DEBUG 3
// on XIAO "TX" - GPIO 0
#define PIN_TX 0
#define PIO_BAUD 115200
// the PIO, and statemachine ?
PIO pio = pio0;
uint sm = 0;
uint offset = 0;
void setup(void){
pinMode(PIN_LED_B, OUTPUT);
digitalWrite(PIN_LED_B, LOW);
pinMode(PIN_DEBUG, OUTPUT);
digitalWrite(PIN_DEBUG, LOW);
// the display setup
displaySetup();
displayPrint("bonjour...");
offset = pio_add_program(pio, &uart_tx_program);
uart_tx_program_init(pio, sm, offset, PIN_TX, PIO_BAUD);
}
uint32_t lastUpdate = 0;
uint32_t updateInterval = 200;
void loop(void){
digitalWrite(PIN_DEBUG, HIGH);
// blocking tx-put:
uart_tx_program_putc(pio, sm, 85);
digitalWrite(PIN_DEBUG, LOW);
// ...
if(lastUpdate + updateInterval < millis()){
lastUpdate = millis();
digitalWrite(PIN_LED_B, !digitalRead(PIN_LED_B));
// displayPrint(spipi_print());
// displayPrint(String(rxCount) + "\n" +
// String(rxSize)
// );
}
}
;
; Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
;
; SPDX-License-Identifier: BSD-3-Clause
;
.program uart_tx
.side_set 1 opt
; An 8n1 UART transmit program.
; OUT pin 0 and side-set pin 0 are both mapped to UART TX pin.
pull side 1 [7] ; Assert stop bit, or stall with line in idle state
set x, 7 side 0 [7] ; Preload bit counter, assert start bit for 8 clocks
bitloop: ; This loop will run 8 times (8n1 UART)
out pins, 1 ; Shift 1 bit from OSR to the first OUT pin
jmp x-- bitloop [6] ; Each loop iteration is 8 cycles.
% c-sdk {
#include "hardware/clocks.h"
static inline void uart_tx_program_init(PIO pio, uint sm, uint offset, uint pin_tx, uint baud) {
// Tell PIO to initially drive output-high on the selected pin, then map PIO
// onto that pin with the IO muxes.
pio_sm_set_pins_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx);
pio_sm_set_pindirs_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx);
pio_gpio_init(pio, pin_tx);
pio_sm_config c = uart_tx_program_get_default_config(offset);
// OUT shifts to right, no autopull
sm_config_set_out_shift(&c, true, false, 32);
// We are mapping both OUT and side-set to the same pin, because sometimes
// we need to assert user data onto the pin (with OUT) and sometimes
// assert constant values (start/stop bit)
sm_config_set_out_pins(&c, pin_tx, 1);
sm_config_set_sideset_pins(&c, pin_tx);
// We only need TX, so get an 8-deep FIFO!
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
// SM transmits 1 bit per 8 execution cycles.
float div = (float)clock_get_hz(clk_sys) / (8 * baud);
sm_config_set_clkdiv(&c, div);
pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true);
}
static inline void uart_tx_program_putc(PIO pio, uint sm, char c) {
pio_sm_put_blocking(pio, sm, (uint32_t)c);
}
static inline void uart_tx_program_puts(PIO pio, uint sm, const char *s) {
while (*s)
uart_tx_program_putc(pio, sm, *s++);
}
%}
\ No newline at end of file
// -------------------------------------------------- //
// This file is autogenerated by pioasm; do not edit! //
// -------------------------------------------------- //
#pragma once
#if !PICO_NO_HARDWARE
#include "hardware/pio.h"
#endif
// ------- //
// uart_tx //
// ------- //
#define uart_tx_wrap_target 0
#define uart_tx_wrap 3
static const uint16_t uart_tx_program_instructions[] = {
// .wrap_target
0x9fa0, // 0: pull block side 1 [7]
0xf727, // 1: set x, 7 side 0 [7]
0x6001, // 2: out pins, 1
0x0642, // 3: jmp x--, 2 [6]
// .wrap
};
#if !PICO_NO_HARDWARE
static const struct pio_program uart_tx_program = {
.instructions = uart_tx_program_instructions,
.length = 4,
.origin = -1,
};
static inline pio_sm_config uart_tx_program_get_default_config(uint offset) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + uart_tx_wrap_target, offset + uart_tx_wrap);
sm_config_set_sideset(&c, 2, true, false);
return c;
}
#include "hardware/clocks.h"
static inline void uart_tx_program_init(PIO pio, uint sm, uint offset, uint pin_tx, uint baud) {
// Tell PIO to initially drive output-high on the selected pin, then map PIO
// onto that pin with the IO muxes.
pio_sm_set_pins_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx);
pio_sm_set_pindirs_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx);
pio_gpio_init(pio, pin_tx);
pio_sm_config c = uart_tx_program_get_default_config(offset);
// OUT shifts to right, no autopull
sm_config_set_out_shift(&c, true, false, 32);
// We are mapping both OUT and side-set to the same pin, because sometimes
// we need to assert user data onto the pin (with OUT) and sometimes
// assert constant values (start/stop bit)
sm_config_set_out_pins(&c, pin_tx, 1);
sm_config_set_sideset_pins(&c, pin_tx);
// We only need TX, so get an 8-deep FIFO!
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
// SM transmits 1 bit per 8 execution cycles.
float div = (float)clock_get_hz(clk_sys) / (8 * baud);
sm_config_set_clkdiv(&c, div);
pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true);
}
static inline void uart_tx_program_putc(PIO pio, uint sm, char c) {
pio_sm_put_blocking(pio, sm, (uint32_t)c);
}
static inline void uart_tx_program_puts(PIO pio, uint sm, const char *s) {
while (*s)
uart_tx_program_putc(pio, sm, *s++);
}
#endif
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment