Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ App|Description
[pio_ws2812](pio/ws2812) | Example of driving a string of WS2812 addressable RGB LEDs.
[pio_ws2812_parallel](pio/ws2812) | Examples of driving multiple strings of WS2812 addressable RGB LEDs efficiently.
[pio_addition](pio/addition) | Add two integers together using PIO. Only around 8 billion times slower than Cortex-M0+.
[pio_rs422_tx](pio/rs422_tx) | Modifies the pio_uart_tx sample to send "Hello, world!" with RS-422 transmit functionality without an external IC.

### PWM

Expand Down
1 change: 1 addition & 0 deletions pio/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ if (TARGET hardware_pio)
add_subdirectory_exclude_platforms(pwm)
add_subdirectory_exclude_platforms(quadrature_encoder)
add_subdirectory_exclude_platforms(quadrature_encoder_substep)
add_subdirectory_exclude_platforms(rs422_tx)
add_subdirectory_exclude_platforms(spi)
add_subdirectory_exclude_platforms(squarewave)
add_subdirectory_exclude_platforms(st7789_lcd)
Expand Down
11 changes: 11 additions & 0 deletions pio/rs422_tx/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
add_executable(pio_rs422_tx)

pico_generate_pio_header(pio_rs422_tx ${CMAKE_CURRENT_LIST_DIR}/rs422_tx.pio)

target_sources(pio_rs422_tx PRIVATE rs422_tx.c)

target_link_libraries(pio_rs422_tx PRIVATE pico_stdlib hardware_pio)
pico_add_extra_outputs(pio_rs422_tx)

# add url via pico_set_program_url
example_auto_set_url(pio_rs422_tx)
48 changes: 48 additions & 0 deletions pio/rs422_tx/rs422_tx.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

#include "pico/stdlib.h"
#include "hardware/pio.h"
#include "rs422_tx.pio.h"

// Defines the GPIO pins for PIO communication.
// PIO_TXP_PIN is the positive pin.
// PIO_TXM_PIN is the negative pin and must be the next pin in sequence.
#define PIO_TXP_PIN 0
#define PIO_TXM_PIN 1

// Check the pin is compatible with the platform
#if (PIO_TXM_PIN) != (PIO_TXP_PIN + 1)
#error "PIO_TXM_PIN must be the next pin after PIO_TXP_PIN."
#endif
#if (PIO_TXM_PIN) >= NUM_BANK0_GPIOS
#error "Attempting to use a pin>=32 on a platform that does not support it"
#endif

int main() {
// This is the same as the default UART baud rate on Pico
const uint SERIAL_BAUD = 115200;

PIO pio;
uint sm;
uint offset;

// This will find a free pio and state machine for our program and load it for us
// We use pio_claim_free_sm_and_add_program_for_gpio_range (for_gpio_range variant)
// so we will get a PIO instance suitable for addressing gpios >= 32 if needed and supported by the hardware
bool success = pio_claim_free_sm_and_add_program_for_gpio_range(&rs422_tx_program, &pio, &sm, &offset, PIO_TXP_PIN, 2, true);
hard_assert(success);

rs422_tx_program_init(pio, sm, offset, PIO_TXP_PIN, SERIAL_BAUD);

while (true) {
rs422_tx_program_puts(pio, sm, "Hello, world! (from PIO!)\r\n");
sleep_ms(1000);
}

// This will free resources and unload our program
pio_remove_program_and_unclaim_sm(&rs422_tx_program, pio, sm, offset);
}
77 changes: 77 additions & 0 deletions pio/rs422_tx/rs422_tx.pio
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
;
; Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
;
; SPDX-License-Identifier: BSD-3-Clause
;
.pio_version 0 // only requires PIO version 0

.program rs422_tx
.side_set 2 opt

; An 8n1 UART transmit program.
; OUT pin 0-1 are mapped to RS422 TX+ and TX- pin.

pull side 0b01 [3] ; Assert stop bit, or stall with line in idle state
nop
nop
nop
nop
set x, 7 side 0b10 [3] ; Preload bit counter, assert start bit
nop
nop
nop
bitloop: ; This loop will run 8 times (8n1)
out y, 1 ; Shift 1 bit from OSR to the Y register
jmp !y put0
put1:
jmp next side 0b01 [3]
put0:
nop side 0b10 [3]
next:
nop
jmp x-- bitloop


% c-sdk {
#include "hardware/clocks.h"

static inline void rs422_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_consecutive_pindirs(pio, sm, pin_tx, 2, true);
for ( uint i = 0;i<2;i++ ) {
pio_gpio_init(pio, pin_tx + i);
}

pio_sm_config c = rs422_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, 2);
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 rs422_tx_program_putc(PIO pio, uint sm, char c) {
pio_sm_put_blocking(pio, sm, (uint32_t)c);
}

static inline void rs422_tx_program_puts(PIO pio, uint sm, const char *s) {
while (*s)
rs422_tx_program_putc(pio, sm, *s++);
}

%}