Skip to content

Commit

Permalink
S88: replaced bitbanging by using a PIO state machine
Browse files Browse the repository at this point in the history
  • Loading branch information
reinder committed Aug 27, 2024
1 parent 2bba69a commit aa0bcee
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 50 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ add_executable(traintastic-cs
pico_generate_pio_header(traintastic-cs
${CMAKE_CURRENT_LIST_DIR}/src/xpressnet/xpressnet.pio
)
pico_generate_pio_header(traintastic-cs ${CMAKE_CURRENT_LIST_DIR}/src/s88/s88.pio)

# pull in common dependencies
target_link_libraries(traintastic-cs
Expand Down
6 changes: 4 additions & 2 deletions src/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@
#define TRAINTASTIC_CS_UART uart0

//#define S88_PIN_POWER
#define S88_PIN_RESET 13
#define S88_PIN_LOAD 12
#define S88_PIN_DATA 10
#define S88_PIN_CLOCK 11
#define S88_PIN_LOAD 12
#define S88_PIN_RESET 13
#define S88_PIO pio0
#define S88_SM 2

#define XPRESSNET_PIN_POWER PICO_DEFAULT_LED_PIN // LED for testing now
#define XPRESSNET_PIN_RX 14
Expand Down
112 changes: 64 additions & 48 deletions src/s88/s88.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,36 +20,51 @@
*/

#include "s88.hpp"
#include "s88.pio.h"
#include <algorithm>
#include <pico/stdlib.h>
#include <hardware/clocks.h>
#include <hardware/pio.h>
#include "../config.hpp"
#include "../traintasticcs/input.hpp"
#include "../utils/time.hpp"

#define CLOCK_TICK 100 // us

namespace S88 {

static bool g_enabled = false;
static uint16_t g_inputCount;
static absolute_time_t g_nextScan;
static uint g_fifoRead;
static uint g_inputIndex;

#define CLOCK_FREQUENCY 10000

void init()
{
//gpio_init(S88_PIN_POWER);
//gpio_set_dir(S88_PIN_POWER, GPIO_OUT);

gpio_init(S88_PIN_RESET);
gpio_set_dir(S88_PIN_RESET, GPIO_OUT);
// setup pio:
pio_gpio_init(S88_PIO, S88_PIN_DATA);
pio_gpio_init(S88_PIO, S88_PIN_CLOCK);
pio_gpio_init(S88_PIO, S88_PIN_LOAD);
pio_gpio_init(S88_PIO, S88_PIN_RESET);

pio_sm_set_consecutive_pindirs(S88_PIO, S88_SM, S88_PIN_CLOCK, 3, true);

uint offset = pio_add_program(S88_PIO, &s88_program);
pio_sm_config c = s88_program_get_default_config(offset);

gpio_init(S88_PIN_LOAD);
gpio_set_dir(S88_PIN_LOAD, GPIO_OUT);
sm_config_set_set_pins(&c, S88_PIN_CLOCK, 3);
sm_config_set_sideset_pins(&c, S88_PIN_CLOCK);
sm_config_set_in_pins(&c, S88_PIN_DATA);

gpio_init(S88_PIN_DATA);
gpio_set_dir(S88_PIN_DATA, GPIO_IN);
sm_config_set_out_shift(&c, true, true, 32); // right shift, autopush

gpio_init(S88_PIN_CLOCK);
gpio_set_dir(S88_PIN_CLOCK, GPIO_OUT);
gpio_put(S88_PIN_CLOCK, 1);
float div = (float)clock_get_hz(clk_sys) / (4 * CLOCK_FREQUENCY);
sm_config_set_clkdiv(&c, div);

pio_sm_init(S88_PIO, S88_SM, offset, &c);
}

bool enabled()
Expand All @@ -61,9 +76,18 @@ void enable(uint8_t moduleCount)
{
//gpio_put(S88_PIN_POWER, 1);

pio_sm_set_enabled(S88_PIO, S88_SM, false);

pio_sm_clear_fifos(S88_PIO, S88_SM);

pio_sm_restart(S88_PIO, S88_SM);

pio_sm_set_enabled(S88_PIO, S88_SM, true);

g_inputCount = moduleCount * 8;
g_enabled = true;
g_nextScan = make_timeout_time_ms(1000);
g_fifoRead = 0;
}

void disable()
Expand All @@ -85,46 +109,38 @@ void process()
return;
}

// bit bang test, verify if we can read it

gpio_put(S88_PIN_CLOCK, 0);
sleep_us(CLOCK_TICK * 2);
gpio_put(S88_PIN_LOAD, 1);
sleep_us(CLOCK_TICK);
gpio_put(S88_PIN_CLOCK, 1);
sleep_us(CLOCK_TICK);
gpio_put(S88_PIN_CLOCK, 0);
sleep_us(CLOCK_TICK);
gpio_put(S88_PIN_RESET, 1);
sleep_us(CLOCK_TICK);
gpio_put(S88_PIN_RESET, 0);
sleep_us(CLOCK_TICK);
gpio_put(S88_PIN_LOAD, 0);

TraintasticCS::Input::updateState(
TraintasticCS::InputChannel::S88,
1,
gpio_get(S88_PIN_DATA) ? TraintasticCS::InputState::High : TraintasticCS::InputState::Low);

sleep_us(CLOCK_TICK);

for(uint8_t address = 2; address <= g_inputCount; ++address)
{
gpio_put(S88_PIN_CLOCK, 1);
sleep_us(CLOCK_TICK);

TraintasticCS::Input::updateState(
TraintasticCS::InputChannel::S88,
address,
gpio_get(S88_PIN_DATA) ? TraintasticCS::InputState::High : TraintasticCS::InputState::Low);
constexpr uint wordSize = 32;

gpio_put(S88_PIN_CLOCK, 0);
sleep_us(CLOCK_TICK);
while(g_fifoRead != 0 && !pio_sm_is_rx_fifo_empty(S88_PIO, S88_SM))
{
auto value = pio_sm_get(S88_PIO, S88_SM);
uint bitsToRead = std::min(g_inputCount - g_inputIndex, wordSize);

if(bitsToRead < wordSize)
{
// values are shifted in form the right, align them left
value >>= wordSize - bitsToRead;
}

for(;bitsToRead != 0; --bitsToRead)
{
TraintasticCS::Input::updateState(
TraintasticCS::InputChannel::S88,
1 + g_inputIndex,
(value & 1) ? TraintasticCS::InputState::High : TraintasticCS::InputState::Low);
value >>= 1;
g_inputIndex++;
}

g_fifoRead--;
}

gpio_put(S88_PIN_CLOCK, 1);

g_nextScan = make_timeout_time_ms(10);
if(g_fifoRead == 0) // trigger next scan
{
pio_sm_put(S88_PIO, S88_SM, g_inputCount - 2);
g_fifoRead = 1 + (g_inputCount / wordSize); // round up, at multiple of wordSize there is a dummy push
g_inputIndex = 0;
}
}

}
37 changes: 37 additions & 0 deletions src/s88/s88.pio
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
;
; This file is part of the Traintastic CS firmware,
; see <https://github.com/traintastic/traintastic-cs-firmware>.
;
; Copyright (C) 2024 Reinder Feenstra
;
; This program is free software; you can redistribute it and/or
; modify it under the terms of the GNU General Public License
; as published by the Free Software Foundation; either version 2
; of the License, or (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; if not, write to the Free Software
; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

.program s88
.side_set 1 opt

pull ; get number of bits to read
mov x, osr ; set x to number of bits to read
set pins, 0b010 [1] ; load high
set pins, 0b011 [1] ; clock high
in pins, 1 side 0 ; sample bit, clock low
set pins, 0b110 [1] ; reset high
set pins, 0b010 [1] ; reset low
set pins, 0b000 [1] ; load low
loop:
set pins, 0b001 [1] ; clock high
in pins, 1 side 0 ; sample bit, clock low
jmp x-- loop ; loop until a bits are sampled
set pins, 0b001 ; clock high
push ; push the remaining bits

0 comments on commit aa0bcee

Please sign in to comment.