Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: SoftSerial SDFileSystem mbed wave_player
MySoftSerial.cpp@21:2a91babf5a6d, 2017-05-16 (annotated)
- Committer:
- Desertification
- Date:
- Tue May 16 19:29:56 2017 +0000
- Revision:
- 21:2a91babf5a6d
- Parent:
- 20:d2a8daeb6eb7
- Child:
- 22:c821bfae25d7
finding rx bug
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| Thomas Cauwelier |
15:75f9bd5d7659 | 1 | // |
| Thomas Cauwelier |
15:75f9bd5d7659 | 2 | // Created by thoma on 10-May-17. |
| Thomas Cauwelier |
15:75f9bd5d7659 | 3 | // |
| Thomas Cauwelier |
15:75f9bd5d7659 | 4 | |
| Thomas Cauwelier |
15:75f9bd5d7659 | 5 | #include "MySoftSerial.h" |
| Thomas Cauwelier |
17:8683abdc1912 | 6 | #include "Manchester.h" |
| Thomas Cauwelier |
15:75f9bd5d7659 | 7 | |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 8 | |
| Desertification | 16:1a0589d846bf | 9 | MySoftSerial::MySoftSerial(PinName TX, PinName RX, const char *name) : SoftSerial(TX, RX, name) { |
| Desertification | 21:2a91babf5a6d | 10 | max_time_between_transmission_us = 10000; |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 11 | calc_required_correction_symbols(); |
| Thomas Cauwelier |
17:8683abdc1912 | 12 | format(16, SoftSerial::None, 1); |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 13 | start_bits = 4; |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 14 | dc_offset_timer.reset(); |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 15 | dc_offset_timer.start(); |
| Desertification | 21:2a91babf5a6d | 16 | overhead_us = 200 * 1000000 / SystemCoreClock; |
| Desertification | 21:2a91babf5a6d | 17 | |
| Desertification | 21:2a91babf5a6d | 18 | txticker.detach(); |
| Desertification | 21:2a91babf5a6d | 19 | rxticker.detach(); |
| Desertification | 21:2a91babf5a6d | 20 | if (TX != NC) { |
| Desertification | 21:2a91babf5a6d | 21 | txticker.attach(this, &MySoftSerial::tx_handler); |
| Desertification | 21:2a91babf5a6d | 22 | } |
| Desertification | 21:2a91babf5a6d | 23 | if (RX != NC) { |
| Desertification | 21:2a91babf5a6d | 24 | rxticker.attach(this, &MySoftSerial::rx_handler); |
| Desertification | 21:2a91babf5a6d | 25 | rx->fall(this, &MySoftSerial::rx_gpio_irq_handler); |
| Desertification | 21:2a91babf5a6d | 26 | } |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 27 | } |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 28 | |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 29 | void MySoftSerial::calc_required_correction_symbols() { |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 30 | required_correction_transmissions = (int) ceil(30000.0 / (16 * bit_period)); |
| Thomas Cauwelier |
15:75f9bd5d7659 | 31 | } |
| Thomas Cauwelier |
15:75f9bd5d7659 | 32 | |
| Thomas Cauwelier |
15:75f9bd5d7659 | 33 | MySoftSerial::~MySoftSerial() { |
| Thomas Cauwelier |
15:75f9bd5d7659 | 34 | |
| Thomas Cauwelier |
15:75f9bd5d7659 | 35 | } |
| Thomas Cauwelier |
15:75f9bd5d7659 | 36 | |
| Thomas Cauwelier |
15:75f9bd5d7659 | 37 | int MySoftSerial::putc(int c) { |
| Thomas Cauwelier |
17:8683abdc1912 | 38 | c = Manchester::encode(c); |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 39 | // check if last transmission was not too long ago |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 40 | dc_offset_timer.stop(); |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 41 | if (dc_offset_timer.read_us() > max_time_between_transmission_us) { |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 42 | // transmission was too long ago, must correct the dc offset |
| Thomas Cauwelier |
19:822d93e0bf34 | 43 | correct_dc_offset(); |
| Thomas Cauwelier |
19:822d93e0bf34 | 44 | } |
| Thomas Cauwelier |
15:75f9bd5d7659 | 45 | return _putc(c); |
| Thomas Cauwelier |
15:75f9bd5d7659 | 46 | } |
| Thomas Cauwelier |
15:75f9bd5d7659 | 47 | |
| Desertification | 21:2a91babf5a6d | 48 | int MySoftSerial::_putc(int c) |
| Desertification | 21:2a91babf5a6d | 49 | { |
| Desertification | 21:2a91babf5a6d | 50 | while(!writeable()); |
| Desertification | 21:2a91babf5a6d | 51 | prepare_tx(c); |
| Desertification | 21:2a91babf5a6d | 52 | tx_bit = 0; |
| Desertification | 21:2a91babf5a6d | 53 | txticker.prime(); |
| Desertification | 21:2a91babf5a6d | 54 | tx_handler(); |
| Desertification | 21:2a91babf5a6d | 55 | return 0; |
| Desertification | 21:2a91babf5a6d | 56 | } |
| Desertification | 21:2a91babf5a6d | 57 | |
| Thomas Cauwelier |
15:75f9bd5d7659 | 58 | int MySoftSerial::getc() { |
| Thomas Cauwelier |
19:822d93e0bf34 | 59 | int character = _getc(); |
| Thomas Cauwelier |
19:822d93e0bf34 | 60 | return Manchester::decode(character); |
| Thomas Cauwelier |
17:8683abdc1912 | 61 | } |
| Thomas Cauwelier |
17:8683abdc1912 | 62 | |
| Thomas Cauwelier |
17:8683abdc1912 | 63 | void MySoftSerial::prepare_tx(int c) { |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 64 | // _char is transmitted lsb first |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 65 | _char = c << start_bits; // make room for start bits |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 66 | _char |= 0b1010; //add start bits (lsb first) |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 67 | _char |= 0xFFFF << (start_bits + _bits); // pad with stop bits |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 68 | _char &= ~(1<<_total_bits); // zero after last stop bit ~(1<<_total_bits) = ...111101111... |
| Thomas Cauwelier |
15:75f9bd5d7659 | 69 | } |
| Thomas Cauwelier |
17:8683abdc1912 | 70 | |
| Thomas Cauwelier |
17:8683abdc1912 | 71 | void MySoftSerial::baud(int baudrate) { |
| Thomas Cauwelier |
17:8683abdc1912 | 72 | SoftSerial::baud(baudrate); |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 73 | calc_required_correction_symbols(); |
| Thomas Cauwelier |
17:8683abdc1912 | 74 | } |
| Thomas Cauwelier |
17:8683abdc1912 | 75 | |
| Thomas Cauwelier |
17:8683abdc1912 | 76 | int MySoftSerial::readable() { |
| Thomas Cauwelier |
17:8683abdc1912 | 77 | return SoftSerial::readable(); |
| Thomas Cauwelier |
17:8683abdc1912 | 78 | } |
| Thomas Cauwelier |
17:8683abdc1912 | 79 | |
| Thomas Cauwelier |
17:8683abdc1912 | 80 | int MySoftSerial::writeable() { |
| Thomas Cauwelier |
17:8683abdc1912 | 81 | return SoftSerial::writeable(); |
| Thomas Cauwelier |
17:8683abdc1912 | 82 | } |
| Thomas Cauwelier |
19:822d93e0bf34 | 83 | |
| Thomas Cauwelier |
19:822d93e0bf34 | 84 | void MySoftSerial::correct_dc_offset() { |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 85 | for (int i = 0; i < required_correction_transmissions; ++i) { |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 86 | //16 bit_periods |
| Thomas Cauwelier |
19:822d93e0bf34 | 87 | tx->write(0); |
| Thomas Cauwelier |
19:822d93e0bf34 | 88 | wait_us(bit_period * 12); // send 12 zeros |
| Thomas Cauwelier |
19:822d93e0bf34 | 89 | tx->write(1); |
| Thomas Cauwelier |
19:822d93e0bf34 | 90 | wait_us(bit_period * 4); // send 4 ones |
| Thomas Cauwelier |
19:822d93e0bf34 | 91 | } |
| Thomas Cauwelier |
19:822d93e0bf34 | 92 | } |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 93 | |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 94 | void MySoftSerial::rx_gpio_irq_handler(void) { |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 95 | rxticker.prime(); |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 96 | rxticker.setNext(bit_period + (bit_period >> 1) - overhead_us); // jump 1.5 bit periods |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 97 | rx->fall(NULL); |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 98 | rxticker.attach(this, &MySoftSerial::rx_detect_start); |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 99 | start_bit = 1; // start from second bit |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 100 | rx_bit = 0; |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 101 | rx_error = false; |
| Desertification | 21:2a91babf5a6d | 102 | printf("q\n"); |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 103 | } |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 104 | |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 105 | void MySoftSerial::rx_detect_start(void){ |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 106 | int val = rx->read(); |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 107 | |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 108 | // check start pattern |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 109 | // todo store pattern in array or int |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 110 | bool ok; |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 111 | switch(start_bit){ |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 112 | case 0: |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 113 | ok = val==0; |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 114 | break; |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 115 | case 1: |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 116 | ok = val==1; |
| Desertification | 21:2a91babf5a6d | 117 | printf("a\n"); |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 118 | break; |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 119 | case 2: |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 120 | ok = val==0; |
| Desertification | 21:2a91babf5a6d | 121 | printf("b\n"); |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 122 | break; |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 123 | case 3: |
| Desertification | 21:2a91babf5a6d | 124 | printf("c\n"); |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 125 | ok = val==1; |
| Desertification | 21:2a91babf5a6d | 126 | rxticker.attach(this, &MySoftSerial::rx_handler); |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 127 | break; |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 128 | default: |
| Desertification | 21:2a91babf5a6d | 129 | printf("d\n"); |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 130 | ok = false; |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 131 | } |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 132 | |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 133 | if(ok){ |
| Desertification | 21:2a91babf5a6d | 134 | start_bit++; |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 135 | rxticker.setNext(bit_period); |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 136 | } else { |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 137 | // start pattern was not correct, this is not a data packet |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 138 | rxticker.detach(); |
| Desertification | 21:2a91babf5a6d | 139 | rx->fall(this, &MySoftSerial::rx_gpio_irq_handler); |
| Desertification | 21:2a91babf5a6d | 140 | } |
| Desertification | 21:2a91babf5a6d | 141 | } |
| Desertification | 21:2a91babf5a6d | 142 | |
| Desertification | 21:2a91babf5a6d | 143 | void MySoftSerial::rx_handler(void) { |
| Desertification | 21:2a91babf5a6d | 144 | //Receive data |
| Desertification | 21:2a91babf5a6d | 145 | printf("%i\n",rx_bit); |
| Desertification | 21:2a91babf5a6d | 146 | int val = rx->read(); |
| Desertification | 21:2a91babf5a6d | 147 | |
| Desertification | 21:2a91babf5a6d | 148 | rxticker.setNext(bit_period); |
| Desertification | 21:2a91babf5a6d | 149 | rx_bit++; |
| Desertification | 21:2a91babf5a6d | 150 | |
| Desertification | 21:2a91babf5a6d | 151 | |
| Desertification | 21:2a91babf5a6d | 152 | if (rx_bit <= _bits) { |
| Desertification | 21:2a91babf5a6d | 153 | read_buffer |= val << (rx_bit - 1); |
| Desertification | 21:2a91babf5a6d | 154 | return; |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 155 | } |
| Desertification | 21:2a91babf5a6d | 156 | |
| Desertification | 21:2a91babf5a6d | 157 | //Receive parity |
| Desertification | 21:2a91babf5a6d | 158 | bool parity_count; |
| Desertification | 21:2a91babf5a6d | 159 | if (rx_bit == _bits + 1) { |
| Desertification | 21:2a91babf5a6d | 160 | switch (_parity) { |
| Desertification | 21:2a91babf5a6d | 161 | case Forced1: |
| Desertification | 21:2a91babf5a6d | 162 | if (val == 0) |
| Desertification | 21:2a91babf5a6d | 163 | rx_error = true; |
| Desertification | 21:2a91babf5a6d | 164 | return; |
| Desertification | 21:2a91babf5a6d | 165 | case Forced0: |
| Desertification | 21:2a91babf5a6d | 166 | if (val == 1) |
| Desertification | 21:2a91babf5a6d | 167 | rx_error = true; |
| Desertification | 21:2a91babf5a6d | 168 | return; |
| Desertification | 21:2a91babf5a6d | 169 | case Even: |
| Desertification | 21:2a91babf5a6d | 170 | case Odd: |
| Desertification | 21:2a91babf5a6d | 171 | parity_count = val; |
| Desertification | 21:2a91babf5a6d | 172 | for (int i = 0; i<_bits; i++) { |
| Desertification | 21:2a91babf5a6d | 173 | if (((read_buffer >> i) & 0x01) == 1) |
| Desertification | 21:2a91babf5a6d | 174 | parity_count = !parity_count; |
| Desertification | 21:2a91babf5a6d | 175 | } |
| Desertification | 21:2a91babf5a6d | 176 | if ((parity_count) && (_parity == Even)) |
| Desertification | 21:2a91babf5a6d | 177 | rx_error = true; |
| Desertification | 21:2a91babf5a6d | 178 | if ((!parity_count) && (_parity == Odd)) |
| Desertification | 21:2a91babf5a6d | 179 | rx_error = true; |
| Desertification | 21:2a91babf5a6d | 180 | return; |
| Desertification | 21:2a91babf5a6d | 181 | } |
| Desertification | 21:2a91babf5a6d | 182 | } |
| Desertification | 21:2a91babf5a6d | 183 | |
| Desertification | 21:2a91babf5a6d | 184 | //Receive stop |
| Desertification | 21:2a91babf5a6d | 185 | if (rx_bit < _bits + (bool)_parity + _stop_bits) { |
| Desertification | 21:2a91babf5a6d | 186 | if (!val) |
| Desertification | 21:2a91babf5a6d | 187 | rx_error = true; |
| Desertification | 21:2a91babf5a6d | 188 | return; |
| Desertification | 21:2a91babf5a6d | 189 | } |
| Desertification | 21:2a91babf5a6d | 190 | |
| Desertification | 21:2a91babf5a6d | 191 | //The last stop bit |
| Desertification | 21:2a91babf5a6d | 192 | if (!val) |
| Desertification | 21:2a91babf5a6d | 193 | rx_error = true; |
| Desertification | 21:2a91babf5a6d | 194 | |
| Desertification | 21:2a91babf5a6d | 195 | if (!rx_error) { |
| Desertification | 21:2a91babf5a6d | 196 | out_valid = true; |
| Desertification | 21:2a91babf5a6d | 197 | out_buffer = read_buffer; |
| Desertification | 21:2a91babf5a6d | 198 | fpointer[RxIrq].call(); |
| Desertification | 21:2a91babf5a6d | 199 | } |
| Desertification | 21:2a91babf5a6d | 200 | read_buffer = 0; |
| Desertification | 21:2a91babf5a6d | 201 | rxticker.detach(); |
| Desertification | 21:2a91babf5a6d | 202 | rx->fall(this, &MySoftSerial::rx_gpio_irq_handler); |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 203 | } |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 204 | |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 205 | void MySoftSerial::format(int bits, SoftSerial::Parity parity, int stop_bits) { |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 206 | SoftSerial::format(bits, parity, stop_bits); |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 207 | _total_bits = 4 + _bits + _stop_bits; |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 208 | } |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 209 | |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 210 | void MySoftSerial::tx_handler(void) { |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 211 | if (tx_bit == _total_bits) { |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 212 | tx_bit = -1; |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 213 | // transmission done, start measuring time until next transmission |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 214 | dc_offset_timer.reset(); |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 215 | dc_offset_timer.start(); |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 216 | |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 217 | fpointer[TxIrq].call(); |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 218 | return; |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 219 | } |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 220 | |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 221 | //Flip output |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 222 | int cur_out = tx->read(); |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 223 | tx->write(!cur_out); |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 224 | |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 225 | //Calculate when to do it again |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 226 | int count = bit_period; |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 227 | tx_bit++; |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 228 | while(((_char >> tx_bit) & 0x01) == !cur_out) { |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 229 | count+=bit_period; |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 230 | tx_bit++; |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 231 | } |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 232 | |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 233 | txticker.setNext(count); |
| Thomas Cauwelier |
20:d2a8daeb6eb7 | 234 | } |