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 txPin=-1, int rxPin=-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 
63  protected:
64  PIO pio;
65  uint sm_rx;
66  uint sm_tx;
67  uint baud;
68  int offset;
69  int peekValue=-1;
70 
71  void setupRx(uint pin) {
72  pio_sm_set_consecutive_pindirs(pio, sm_rx, pin, 1, false);
73  pio_gpio_init(pio, pin);
74  gpio_pull_up(pin);
75 
76  int offset = pio_add_program(pio, &pio_uart_rx_program);
77  pio_sm_config c = pio_uart_rx_program_get_default_config(offset);
78  sm_config_set_in_pins(&c, pin); // for WAIT, IN
79  sm_config_set_jmp_pin(&c, pin); // for JMP
80  // Shift to right, autopull disabled
81  sm_config_set_in_shift(&c, true, false, 32);
82  // Deeper FIFO as we're not doing any TX
83  sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
84  // SM transmits 1 bit per 8 execution cycles.
85  float div = (float)clock_get_hz(clk_sys) / (8 * baud);
86  sm_config_set_clkdiv(&c, div);
87 
88  pio_sm_init(pio, sm_rx, offset, &c);
89  pio_sm_set_enabled(pio, sm_rx, true);
90  }
91 
92  void setupTx(uint pin_tx) {
93  // Tell PIO to initially drive output-high on the selected pin, then map PIO
94  // onto that pin with the IO muxes.
95  pio_sm_set_pins_with_mask(pio, sm_tx, 1u << pin_tx, 1u << pin_tx);
96  pio_sm_set_pindirs_with_mask(pio, sm_tx, 1u << pin_tx, 1u << pin_tx);
97  pio_gpio_init(pio, pin_tx);
98 
99  int offset = pio_add_program(pio, &pio_uart_tx_program);
100  pio_sm_config c = pio_uart_tx_program_get_default_config(offset);
101 
102  // OUT shifts to right, no autopull
103  sm_config_set_out_shift(&c, true, false, 32);
104 
105  // We are mapping both OUT and side-set to the same pin, because sometimes
106  // we need to assert user data onto the pin (with OUT) and sometimes
107  // assert constant values (start/stop bit)
108  sm_config_set_out_pins(&c, pin_tx, 1);
109  sm_config_set_sideset_pins(&c, pin_tx);
110 
111  // We only need TX, so get an 8-deep FIFO!
112  sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
113 
114  // SM transmits 1 bit per 8 execution cycles.
115  float div = (float)clock_get_hz(clk_sys) / (8 * baud);
116  sm_config_set_clkdiv(&c, div);
117 
118  pio_sm_init(pio, sm_tx, offset, &c);
119  pio_sm_set_enabled(pio, sm_tx, true);
120  }
121 };
Software Serial Arduino Stream which uses the Pico PIO.
Definition: SoftwareSerial.h:13