Initial Release
This commit is contained in:
16
pio/uart_rx/CMakeLists.txt
Normal file
16
pio/uart_rx/CMakeLists.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
add_executable(pio_uart_rx)
|
||||
|
||||
pico_generate_pio_header(pio_uart_rx ${CMAKE_CURRENT_LIST_DIR}/uart_rx.pio)
|
||||
|
||||
target_sources(pio_uart_rx PRIVATE uart_rx.c)
|
||||
|
||||
target_link_libraries(pio_uart_rx PRIVATE
|
||||
pico_stdlib
|
||||
pico_multicore
|
||||
hardware_pio
|
||||
)
|
||||
|
||||
pico_add_extra_outputs(pio_uart_rx)
|
||||
|
||||
# add url via pico_set_program_url
|
||||
example_auto_set_url(pio_uart_rx)
|
||||
60
pio/uart_rx/uart_rx.c
Normal file
60
pio/uart_rx/uart_rx.c
Normal file
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico/multicore.h"
|
||||
#include "hardware/pio.h"
|
||||
#include "hardware/uart.h"
|
||||
#include "uart_rx.pio.h"
|
||||
|
||||
// This program
|
||||
// - Uses UART1 (the spare UART, by default) to transmit some text
|
||||
// - Uses a PIO state machine to receive that text
|
||||
// - Prints out the received text to the default console (UART0)
|
||||
// This might require some reconfiguration on boards where UART1 is the
|
||||
// default UART.
|
||||
|
||||
#define SERIAL_BAUD PICO_DEFAULT_UART_BAUD_RATE
|
||||
#define HARD_UART_INST uart1
|
||||
|
||||
// You'll need a wire from GPIO4 -> GPIO3
|
||||
#define HARD_UART_TX_PIN 4
|
||||
#define PIO_RX_PIN 3
|
||||
|
||||
// Ask core 1 to print a string, to make things easier on core 0
|
||||
void core1_main() {
|
||||
const char *s = (const char *) multicore_fifo_pop_blocking();
|
||||
uart_puts(HARD_UART_INST, s);
|
||||
}
|
||||
|
||||
int main() {
|
||||
// Console output (also a UART, yes it's confusing)
|
||||
setup_default_uart();
|
||||
printf("Starting PIO UART RX example\n");
|
||||
|
||||
// Set up the hard UART we're going to use to print characters
|
||||
uart_init(HARD_UART_INST, SERIAL_BAUD);
|
||||
gpio_set_function(HARD_UART_TX_PIN, GPIO_FUNC_UART);
|
||||
|
||||
// Set up the state machine we're going to use to receive them.
|
||||
PIO pio = pio0;
|
||||
uint sm = 0;
|
||||
uint offset = pio_add_program(pio, &uart_rx_program);
|
||||
uart_rx_program_init(pio, sm, offset, PIO_RX_PIN, SERIAL_BAUD);
|
||||
|
||||
// Tell core 1 to print some text to uart1 as fast as it can
|
||||
multicore_launch_core1(core1_main);
|
||||
const char *text = "Hello, world from PIO! (Plus 2 UARTs and 2 cores, for complex reasons)\n";
|
||||
multicore_fifo_push_blocking((uint32_t) text);
|
||||
|
||||
// Echo characters received from PIO to the console
|
||||
while (true) {
|
||||
char c = uart_rx_program_getc(pio, sm);
|
||||
putchar(c);
|
||||
}
|
||||
}
|
||||
94
pio/uart_rx/uart_rx.pio
Normal file
94
pio/uart_rx/uart_rx.pio
Normal file
@@ -0,0 +1,94 @@
|
||||
;
|
||||
; 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, autopull 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;
|
||||
}
|
||||
|
||||
%}
|
||||
Reference in New Issue
Block a user