Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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 pio/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ if (NOT PICO_NO_HARDWARE)
add_subdirectory(onewire)
add_subdirectory(pio_blink)
add_subdirectory(pwm)
add_subdirectory(ppm)
add_subdirectory(quadrature_encoder)
add_subdirectory(spi)
add_subdirectory(squarewave)
Expand Down
11 changes: 11 additions & 0 deletions pio/ppm/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
add_executable(pio_ppm)

pico_generate_pio_header(pio_ppm ${CMAKE_CURRENT_LIST_DIR}/ppm.pio)

target_sources(pio_ppm PRIVATE ppm.c)

target_link_libraries(pio_ppm PRIVATE pico_stdlib hardware_pio hardware_clocks)
pico_add_extra_outputs(pio_ppm)

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

/*
* 8-channel Radio Control PPM example
* Output on GPIO3
*
* 0.5ms 5ms 0.5ms 1-2mc 0.5ms 1-2mc
* strobe synchro strobe ch0 value strobe ch1 value
* ______ _______ _______
* |_______...__| |_____________| |___________...
*/
#include <stdio.h>

#include "pico/stdlib.h"
#include "hardware/clocks.h"
#include "hardware/pio.h"
#include "ppm.pio.h"

void set_value_and_log(uint channel, uint value_usec) {
printf("Channel %d is set to value %5.3f ms\r\n", channel, (float)value_usec / 1000.0f);
ppm_set_value(channel, value_usec);

}
int main() {
setup_default_uart();
uint pin = 3;
ppm_program_init(pio0, pin);
while (1) {
set_value_and_log(1, 1100);
set_value_and_log(8, 1800);
sleep_ms(1000);
set_value_and_log(1, 1700);
set_value_and_log(8, 1200);
sleep_ms(1000);
}
}

83 changes: 83 additions & 0 deletions pio/ppm/ppm.pio
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
;
; Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
;
; SPDX-License-Identifier: BSD-3-Clause
;

.program ppm
.side_set 1

set pindirs, 1 side 0; Set pin to output
.wrap_target
out x, 16 side 0
delay0:
jmp x-- delay0 side 0
out x, 16 side 1
delay1:
jmp x-- delay1 side 1
.wrap

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


#define PPM_CHANNELS (8)
struct {
volatile PIO pio;
// 16 MSB - strobe length in microsec
// 16 LSB - gap length in microsec
volatile uint32_t ch_values[PPM_CHANNELS + 1];
volatile uint value_idx;
} ppm_data;

void ppm_handler() {
while (!pio_sm_is_tx_fifo_full(ppm_data.pio, 0)) {
pio_sm_put(ppm_data.pio, 0, ppm_data.ch_values[ppm_data.value_idx]);
ppm_data.value_idx = (ppm_data.value_idx + 1) % (PPM_CHANNELS + 1);
}
}

// 500 microseconds strobe and gap microseconds
#define BUILD_CH_VALUE(gap_us) (((500 - 1) << 16) + (gap_us - 1))

static inline void ppm_program_init(PIO pio, uint pin) {
ppm_data.pio = pio == NULL ? pio0 : pio;
ppm_data.ch_values[0] = BUILD_CH_VALUE(5000);
// Neutral position (1500us) by default
for (int i = 1; i <= PPM_CHANNELS; ++i)
ppm_data.ch_values[i] = BUILD_CH_VALUE(1500);
ppm_data.value_idx = 0;
uint offset = pio_add_program(ppm_data.pio, &ppm_program);
pio_gpio_init(ppm_data.pio, pin);
pio_sm_set_consecutive_pindirs(pio, 0, pin, 1, true);
pio_sm_config pio_conf = ppm_program_get_default_config(offset);
sm_config_set_sideset_pins(&pio_conf, pin);
sm_config_set_set_pins(&pio_conf, 0, 1);
sm_config_set_out_shift(&pio_conf, true, true, 0);
sm_config_set_fifo_join(&pio_conf, PIO_FIFO_JOIN_TX);
pio_sm_init(ppm_data.pio, 0, offset, &pio_conf);
pio_sm_set_clkdiv(ppm_data.pio, 0, (float) clock_get_hz(clk_sys) / 1000000); //1MHz
pio_sm_clear_fifos(ppm_data.pio, 0);
pio_sm_restart(ppm_data.pio, 0);

pio_set_irq0_source_enabled(ppm_data.pio, PIO_INTR_SM0_TXNFULL_LSB, true);
irq_set_exclusive_handler(PIO0_IRQ_0, ppm_handler);
irq_set_enabled(PIO0_IRQ_0, true);
pio_sm_set_enabled(ppm_data.pio, 0, true);
}

/** Sets channel value
*
* @channel_number RC channel number [1..PPM_CHANNELS]
* @value_usec channel vaue [1000, 2000]
*/
static inline void ppm_set_value(uint channel_number, uint value_usec) {
valid_params_if(PIO, channel_number <= PPM_CHANNELS);
valid_params_if(PIO, channel_number >= 1);
valid_params_if(PIO, value_usec <= 2000);
valid_params_if(PIO, value_usec >= 1000);
ppm_data.ch_values[channel_number] = BUILD_CH_VALUE(value_usec);
}
%}