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

pio rx no-irq hello world

parent 168558b7
No related branches found
No related tags found
No related merge requests found
......@@ -12,6 +12,8 @@ So, as for reasonable goals for today, I should basically just try to throw-and-
Well actually, fk it, I will use the online pioasm for the time being...
### UART PIO TX'ing
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...
This should be simple: we have output is
......@@ -32,3 +34,9 @@ So we should be able to to clk/8 : 16MBit/s, and indeed we can see things workin
| 30 | ![img](images/2024-01-03_uart-tx-30mb.png) |
But this is not terribly interesting: we want to see that we can catch words fast enough: the ISR on the RX side is normally where we meet our limits.
### UART PIO RX'ing
So, I should spin up an RX line now and see about firing an interrupt there... I'll get one chip TX'ing at a fixed rate and then start in on no. 2
... doing this using [the blocking example](https://github.com/raspberrypi/pico-examples/blob/master/pio/uart_rx/uart_rx.c) catches *some* bytes, but not that many (at only 1mbaud), and it's perhaps only latching when we *just* catch the byte in time, i.e. if we poll just as the last bit has arrived.
\ No newline at end of file
#include "screen.h"
#include "uart_rx.pio.h"
// using an RP2040 XIAO
// with earle philhower core
// "D10" - GPIO 3
#define PIN_DEBUG 3
// on XIAO "RX" - GPIO 1
#define PIN_RX 1
#define PIO_BAUD 1000000
// 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_rx_program);
uart_rx_program_init(pio, sm, offset, PIN_RX, PIO_BAUD);
}
uint32_t lastUpdate = 0;
uint32_t updateInterval = 200;
void loop(void){
digitalWrite(PIN_DEBUG, !digitalRead(PIN_DEBUG));
uint8_t data = uart_rx_program_getc(pio, sm);
// 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_rx_mini
; Minimum viable 8n1 UART receiver. Wait for the start bit, then sample 8 bits
; with the correct timing.
; IN pin 0 is mapped to the GPIO used as UART RX.
; Autopush must be enabled, with a threshold of 8.
wait 0 pin 0 ; Wait for start bit
set x, 7 [10] ; Preload bit counter, delay until eye of first data bit
bitloop: ; Loop 8 times
in pins, 1 ; Sample data
jmp x-- bitloop [6] ; Each iteration is 8 cycles
% c-sdk {
#include "hardware/clocks.h"
#include "hardware/gpio.h"
static inline void uart_rx_mini_program_init(PIO pio, uint sm, uint offset, uint pin, uint baud) {
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);
pio_gpio_init(pio, pin);
gpio_pull_up(pin);
pio_sm_config c = uart_rx_mini_program_get_default_config(offset);
sm_config_set_in_pins(&c, pin); // for WAIT, IN
// Shift to right, autopush enabled
sm_config_set_in_shift(&c, true, true, 8);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
// 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);
}
%}
.program uart_rx
; Slightly more fleshed-out 8n1 UART receiver which handles framing errors and
; break conditions more gracefully.
; IN pin 0 and JMP pin are both mapped to the GPIO used as UART RX.
start:
wait 0 pin 0 ; Stall until start bit is asserted
set x, 7 [10] ; Preload bit counter, then delay until halfway through
bitloop: ; the first data bit (12 cycles incl wait, set).
in pins, 1 ; Shift data bit into ISR
jmp x-- bitloop [6] ; Loop 8 times, each loop iteration is 8 cycles
jmp pin good_stop ; Check stop bit (should be high)
irq 4 rel ; Either a framing error or a break. Set a sticky flag,
wait 1 pin 0 ; and wait for line to return to idle state.
jmp start ; Don't push data if we didn't see good framing.
good_stop: ; No delay before returning to start; a little slack is
push ; important in case the TX clock is slightly too fast.
% c-sdk {
static inline void uart_rx_program_init(PIO pio, uint sm, uint offset, uint pin, uint baud) {
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);
pio_gpio_init(pio, pin);
gpio_pull_up(pin);
pio_sm_config c = uart_rx_program_get_default_config(offset);
sm_config_set_in_pins(&c, pin); // for WAIT, IN
sm_config_set_jmp_pin(&c, pin); // for JMP
// Shift to right, autopush disabled
sm_config_set_in_shift(&c, true, false, 32);
// Deeper FIFO as we're not doing any TX
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
// 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 char uart_rx_program_getc(PIO pio, uint sm) {
// 8-bit read from the uppermost byte of the FIFO, as data is left-justified
io_rw_8 *rxfifo_shift = (io_rw_8*)&pio->rxf[sm] + 3;
while (pio_sm_is_rx_fifo_empty(pio, sm))
tight_loop_contents();
return (char)*rxfifo_shift;
}
%}
\ 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_rx_mini //
// ------------ //
#define uart_rx_mini_wrap_target 0
#define uart_rx_mini_wrap 3
static const uint16_t uart_rx_mini_program_instructions[] = {
// .wrap_target
0x2020, // 0: wait 0 pin, 0
0xea27, // 1: set x, 7 [10]
0x4001, // 2: in pins, 1
0x0642, // 3: jmp x--, 2 [6]
// .wrap
};
#if !PICO_NO_HARDWARE
static const struct pio_program uart_rx_mini_program = {
.instructions = uart_rx_mini_program_instructions,
.length = 4,
.origin = -1,
};
static inline pio_sm_config uart_rx_mini_program_get_default_config(uint offset) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + uart_rx_mini_wrap_target, offset + uart_rx_mini_wrap);
return c;
}
#include "hardware/clocks.h"
#include "hardware/gpio.h"
static inline void uart_rx_mini_program_init(PIO pio, uint sm, uint offset, uint pin, uint baud) {
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);
pio_gpio_init(pio, pin);
gpio_pull_up(pin);
pio_sm_config c = uart_rx_mini_program_get_default_config(offset);
sm_config_set_in_pins(&c, pin); // for WAIT, IN
// Shift to right, autopush enabled
sm_config_set_in_shift(&c, true, true, 8);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
// 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);
}
#endif
// ------- //
// uart_rx //
// ------- //
#define uart_rx_wrap_target 0
#define uart_rx_wrap 8
static const uint16_t uart_rx_program_instructions[] = {
// .wrap_target
0x2020, // 0: wait 0 pin, 0
0xea27, // 1: set x, 7 [10]
0x4001, // 2: in pins, 1
0x0642, // 3: jmp x--, 2 [6]
0x00c8, // 4: jmp pin, 8
0xc014, // 5: irq nowait 4 rel
0x20a0, // 6: wait 1 pin, 0
0x0000, // 7: jmp 0
0x8020, // 8: push block
// .wrap
};
#if !PICO_NO_HARDWARE
static const struct pio_program uart_rx_program = {
.instructions = uart_rx_program_instructions,
.length = 9,
.origin = -1,
};
static inline pio_sm_config uart_rx_program_get_default_config(uint offset) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + uart_rx_wrap_target, offset + uart_rx_wrap);
return c;
}
static inline void uart_rx_program_init(PIO pio, uint sm, uint offset, uint pin, uint baud) {
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);
pio_gpio_init(pio, pin);
gpio_pull_up(pin);
pio_sm_config c = uart_rx_program_get_default_config(offset);
sm_config_set_in_pins(&c, pin); // for WAIT, IN
sm_config_set_jmp_pin(&c, pin); // for JMP
// Shift to right, autopush disabled
sm_config_set_in_shift(&c, true, false, 32);
// Deeper FIFO as we're not doing any TX
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
// 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 char uart_rx_program_getc(PIO pio, uint sm) {
// 8-bit read from the uppermost byte of the FIFO, as data is left-justified
io_rw_8 *rxfifo_shift = (io_rw_8*)&pio->rxf[sm] + 3;
while (pio_sm_is_rx_fifo_empty(pio, sm))
tight_loop_contents();
return (char)*rxfifo_shift;
}
#endif
\ 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
......@@ -9,7 +9,7 @@
// on XIAO "TX" - GPIO 0
#define PIN_TX 0
#define PIO_BAUD 30000000
#define PIO_BAUD 1000000
// the PIO, and statemachine ?
PIO pio = pio0;
......@@ -38,7 +38,7 @@ void loop(void){
digitalWrite(PIN_DEBUG, HIGH);
// blocking tx-put:
uart_tx_program_putc(pio, sm, 85);
delayMicroseconds(100);
delayMicroseconds(30);
digitalWrite(PIN_DEBUG, LOW);
// ...
if(lastUpdate + updateInterval < millis()){
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment