Pico-Arduino
SoftwareSerial.h
1 #include "hardware/clocks.h"
2 #include "hardware/gpio.h"
3 #include "SoftwareSerial/pio_uart_tx.h"
4 #include "SoftwareSerial/pio_uart_rx.h"
13 class SoftwareSerial : public Stream {
14  public:
15  SoftwareSerial(PIO pio = pio1, uint stateMachineRxIndex=0,uint stateMachineTxIndex=1) {
16  this->pio = pio;
17  this->sm_rx = stateMachineRxIndex;
18  this->sm_tx = stateMachineTxIndex;
19  }
20 
21  void begin(uint baud=9800, int rxPin=-1, int txPin=-1 ){
22  this->baud = baud;
23 
24  if (rxPin >=0 ){
25  setupRx(rxPin);
26  }
27 
28  if (txPin >=0 ){
29  setupTx(txPin);
30  }
31  }
32 
33  virtual int peek() {
34  peekValue = read();
35  return peekValue;
36  }
37 
38  virtual int available() {
39  return pio_sm_get_rx_fifo_level (pio, sm_rx);
40  }
41 
42  virtual int read() {
43  if (peekValue!=-1){
44  int result = peekValue;
45  peekValue = -1;
46  return result;
47  }
48  // 8-bit read from the uppermost byte of the FIFO, as data is left-justified
49  io_rw_8 *rxfifo_shift = (io_rw_8*)&pio->rxf[sm_rx] + 3;
50  if (pio_sm_is_rx_fifo_empty(pio, sm_rx))
51  return -1;
52 
53  tight_loop_contents();
54  return (char)*rxfifo_shift;
55  }
56 
57  virtual size_t write(uint8_t c) {
58  pio_sm_put_blocking(pio, sm_tx, (uint32_t)c);
59  return 1;
60  }
61 
62  using Print::write; // pull in write(str) and write(buf, size) from Print
63  using Print::print; // pull in write(str) and write(buf, size) from Print
64  using Print::println; // pull in write(str) and write(buf, size) from Print
65 
66  protected:
67  PIO pio;
68  uint sm_rx;
69  uint sm_tx;
70  uint baud;
71  int offset;
72  int peekValue=-1;
73 
74  void setupRx(uint pin) {
75  pio_sm_set_consecutive_pindirs(pio, sm_rx, pin, 1, false);
76  pio_gpio_init(pio, pin);
77  gpio_pull_up(pin);
78 
79  int offset = pio_add_program(pio, &pio_uart_rx_program);
80  pio_sm_config c = pio_uart_rx_program_get_default_config(offset);
81  sm_config_set_in_pins(&c, pin); // for WAIT, IN
82  sm_config_set_jmp_pin(&c, pin); // for JMP
83  // Shift to right, autopull disabled
84  sm_config_set_in_shift(&c, true, false, 32);
85  // Deeper FIFO as we're not doing any TX
86  sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
87  // SM transmits 1 bit per 8 execution cycles.
88  float div = (float)clock_get_hz(clk_sys) / (8 * baud);
89  sm_config_set_clkdiv(&c, div);
90 
91  pio_sm_init(pio, sm_rx, offset, &c);
92  pio_sm_set_enabled(pio, sm_rx, true);
93  }
94 
95  void setupTx(uint pin_tx) {
96  // Tell PIO to initially drive output-high on the selected pin, then map PIO
97  // onto that pin with the IO muxes.
98  pio_sm_set_pins_with_mask(pio, sm_tx, 1u << pin_tx, 1u << pin_tx);
99  pio_sm_set_pindirs_with_mask(pio, sm_tx, 1u << pin_tx, 1u << pin_tx);
100  pio_gpio_init(pio, pin_tx);
101 
102  int offset = pio_add_program(pio, &pio_uart_tx_program);
103  pio_sm_config c = pio_uart_tx_program_get_default_config(offset);
104 
105  // OUT shifts to right, no autopull
106  sm_config_set_out_shift(&c, true, false, 32);
107 
108  // We are mapping both OUT and side-set to the same pin, because sometimes
109  // we need to assert user data onto the pin (with OUT) and sometimes
110  // assert constant values (start/stop bit)
111  sm_config_set_out_pins(&c, pin_tx, 1);
112  sm_config_set_sideset_pins(&c, pin_tx);
113 
114  // We only need TX, so get an 8-deep FIFO!
115  sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
116 
117  // SM transmits 1 bit per 8 execution cycles.
118  float div = (float)clock_get_hz(clk_sys) / (8 * baud);
119  sm_config_set_clkdiv(&c, div);
120 
121  pio_sm_init(pio, sm_tx, offset, &c);
122  pio_sm_set_enabled(pio, sm_tx, true);
123  }
124 };
Software Serial Arduino Stream which uses the Pico PIO.
Definition: SoftwareSerial.h:13