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

uart pio begins

parent bb2f1fc5
No related branches found
No related tags found
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