Skip to content

Add an example to trasmit RS422 signal #691

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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)
54 changes: 54 additions & 0 deletions pio/rs422_tx/rs422_tx.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* 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 "Pin number exceeds available GPIOs (30 on RP2040/RP2350A, 48 on RP2350B)"
#endif
#if NUM_BANK0_GPIOS > 30
// On RP2350B, ensure both pins are in the same PIO range
#if !((PIO_TXP_PIN >= 0 && PIO_TXM_PIN < 32) || (PIO_TXP_PIN >= 16 && PIO_TXM_PIN < 48))
#error "On RP2350B, both pins must be in the same PIO range: [0-31] or [16-47]"
#endif
#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);
}
75 changes: 75 additions & 0 deletions pio/rs422_tx/rs422_tx.pio
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
;
; 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 cont side 0b01 [3]
put0:
nop side 0b10 [3]
cont:
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 use side-set to control the RS422 differential pins
// Data bits are determined by conditional jumps based on OUT to Y register
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++);
}

%}