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