SC16IS752 Serial Bridge Arduino Library
Loading...
Searching...
No Matches
SC16IS752.h
1/*
2SC16IS752 driver for Arduino
3*/
4
5#pragma once
6
7#include <SPI.h>
8#include <Wire.h>
9
10#include "Arduino.h"
11#include "SC16IS752Logger.h"
12
13#define SC16IS752_SERIAL_CONFIG(data_bits, parity_code, stop_bits) \
14 ((((data_bits) - 5) & 0x03) | (((parity_code) & 0x03) << 2) | \
15 ((((stop_bits) - 1) & 0x01) << 4))
16
17#ifndef SERIAL_5N1
18#define SERIAL_5N1 SC16IS752_SERIAL_CONFIG(5, 0, 1)
19#endif
20#ifndef SERIAL_6N1
21#define SERIAL_6N1 SC16IS752_SERIAL_CONFIG(6, 0, 1)
22#endif
23#ifndef SERIAL_7N1
24#define SERIAL_7N1 SC16IS752_SERIAL_CONFIG(7, 0, 1)
25#endif
26#ifndef SERIAL_8N1
27#define SERIAL_8N1 SC16IS752_SERIAL_CONFIG(8, 0, 1)
28#endif
29#ifndef SERIAL_5N2
30#define SERIAL_5N2 SC16IS752_SERIAL_CONFIG(5, 0, 2)
31#endif
32#ifndef SERIAL_6N2
33#define SERIAL_6N2 SC16IS752_SERIAL_CONFIG(6, 0, 2)
34#endif
35#ifndef SERIAL_7N2
36#define SERIAL_7N2 SC16IS752_SERIAL_CONFIG(7, 0, 2)
37#endif
38#ifndef SERIAL_8N2
39#define SERIAL_8N2 SC16IS752_SERIAL_CONFIG(8, 0, 2)
40#endif
41#ifndef SERIAL_5E1
42#define SERIAL_5E1 SC16IS752_SERIAL_CONFIG(5, 2, 1)
43#endif
44#ifndef SERIAL_6E1
45#define SERIAL_6E1 SC16IS752_SERIAL_CONFIG(6, 2, 1)
46#endif
47#ifndef SERIAL_7E1
48#define SERIAL_7E1 SC16IS752_SERIAL_CONFIG(7, 2, 1)
49#endif
50#ifndef SERIAL_8E1
51#define SERIAL_8E1 SC16IS752_SERIAL_CONFIG(8, 2, 1)
52#endif
53#ifndef SERIAL_5E2
54#define SERIAL_5E2 SC16IS752_SERIAL_CONFIG(5, 2, 2)
55#endif
56#ifndef SERIAL_6E2
57#define SERIAL_6E2 SC16IS752_SERIAL_CONFIG(6, 2, 2)
58#endif
59#ifndef SERIAL_7E2
60#define SERIAL_7E2 SC16IS752_SERIAL_CONFIG(7, 2, 2)
61#endif
62#ifndef SERIAL_8E2
63#define SERIAL_8E2 SC16IS752_SERIAL_CONFIG(8, 2, 2)
64#endif
65#ifndef SERIAL_5O1
66#define SERIAL_5O1 SC16IS752_SERIAL_CONFIG(5, 1, 1)
67#endif
68#ifndef SERIAL_6O1
69#define SERIAL_6O1 SC16IS752_SERIAL_CONFIG(6, 1, 1)
70#endif
71#ifndef SERIAL_7O1
72#define SERIAL_7O1 SC16IS752_SERIAL_CONFIG(7, 1, 1)
73#endif
74#ifndef SERIAL_8O1
75#define SERIAL_8O1 SC16IS752_SERIAL_CONFIG(8, 1, 1)
76#endif
77#ifndef SERIAL_5O2
78#define SERIAL_5O2 SC16IS752_SERIAL_CONFIG(5, 1, 2)
79#endif
80#ifndef SERIAL_6O2
81#define SERIAL_6O2 SC16IS752_SERIAL_CONFIG(6, 1, 2)
82#endif
83#ifndef SERIAL_7O2
84#define SERIAL_7O2 SC16IS752_SERIAL_CONFIG(7, 1, 2)
85#endif
86#ifndef SERIAL_8O2
87#define SERIAL_8O2 SC16IS752_SERIAL_CONFIG(8, 1, 2)
88#endif
89
90static constexpr uint8_t SC16IS750_I2C_ADDRESS_AA =
91 0x48;
92static constexpr uint8_t SC16IS750_I2C_ADDRESS_AB =
93 0x49;
94static constexpr uint8_t SC16IS750_I2C_ADDRESS_AC =
95 0x4A;
96static constexpr uint8_t SC16IS750_I2C_ADDRESS_AD =
97 0x4B;
98static constexpr uint8_t SC16IS750_I2C_ADDRESS_BA =
99 0x4C;
100static constexpr uint8_t SC16IS750_I2C_ADDRESS_BB =
101 0x4D;
102static constexpr uint8_t SC16IS750_I2C_ADDRESS_BC =
103 0x4E;
104static constexpr uint8_t SC16IS750_I2C_ADDRESS_BD =
105 0x4F;
106static constexpr uint8_t SC16IS750_I2C_ADDRESS_CA =
107 0x50;
108static constexpr uint8_t SC16IS750_I2C_ADDRESS_CB =
109 0x51;
110static constexpr uint8_t SC16IS750_I2C_ADDRESS_CC =
111 0x52;
112static constexpr uint8_t SC16IS750_I2C_ADDRESS_CD =
113 0x53;
114static constexpr uint8_t SC16IS750_I2C_ADDRESS_DA =
115 0x54;
116static constexpr uint8_t SC16IS750_I2C_ADDRESS_DB =
117 0x55;
118static constexpr uint8_t SC16IS750_I2C_ADDRESS_DC =
119 0x56;
120static constexpr uint8_t SC16IS750_I2C_ADDRESS_DD =
121 0x57;
122
127enum SC16IS750_IIR {
128 SC16IS750_RECEIVE_LINE_STATUS_ERROR,
129 SC16IS750_RECEIVE_TIMEOUT_INTERRUPT,
130 SC16IS750_RHR_INTERRUPT,
131 SC16IS750_THR_INTERRUPT,
132 SC16IS750_MODEM_INTERRUPT,
133 SC16IS750_INPUT_PIN_CHANGE_STATE,
134 SC16IS750_RECEIVE_XOFF,
135 SC16IS750_CTS_RTS_CHANGE
136};
137
138static constexpr uint32_t SC16IS752_DEFAULT_SPEED =
139 9600;
140static constexpr uint32_t SC16IS752_DEFAULT_CONFIG =
141 SERIAL_8N1;
142static constexpr uint32_t SC16IS752_DEFAULT_SPI_CLOCK =
143 4000000;
144
171 public:
181
193 class ChannelStream : public Stream {
194 public:
197 : parent_(parent), channel_(channel) {}
198
199 // Stream interface
201 int available() override { return parent_.available(channel_); }
203 int read() override { return parent_.read(channel_); }
205 int peek() override { return parent_.peek(channel_); }
207 void flush() override { parent_.flush(channel_); }
209 size_t write(uint8_t val) override { return parent_.write(channel_, val); }
210 using Print::write;
211
242 void begin(uint32_t baudrate = SC16IS752_DEFAULT_SPEED,
243 uint32_t config = SC16IS752_DEFAULT_CONFIG) {
244 parent_.beginChannel(channel_, baudrate, config);
245 }
247 void end() { parent_.endChannel(channel_); }
249 uint8_t linestate() { return parent_.linestate(channel_); }
252 return parent_.interruptPendingTest(channel_);
253 }
255 int interruptEventTest() { return parent_.interruptEventTest(channel_); }
257 void enableRs485(bool invert_rts) {
258 parent_.enableRs485(channel_, invert_rts);
259 }
260
262 void enableTransmit(uint8_t tx_enable) {
263 parent_.enableTransmit(channel_, tx_enable);
264 }
265
267 void interruptControl(uint8_t int_ena) {
268 parent_.interruptControl(channel_, int_ena);
269 }
270
271 private:
272 SC16IS752& parent_;
273 SC16IS752_Channel channel_;
274 };
275
277 SC16IS752(TwoWire& wire, uint8_t addr = SC16IS750_I2C_ADDRESS_AD,
278 uint32_t crystal_freq_hz = SC16IS750_CRYSTCAL_FREQ)
279 : channel_a_stream(*this, SC16IS752_CHANNEL_A),
280 channel_b_stream(*this, SC16IS752_CHANNEL_B) {
281 device_address_sspin = addr;
282 wire_bus = &wire;
283 spi_bus = nullptr;
284 crystal_freq = crystal_freq_hz;
285 timeout = 1000;
286 peek_buf[SC16IS752_CHANNEL_A] = -1;
287 peek_buf[SC16IS752_CHANNEL_B] = -1;
288 peek_flag[SC16IS752_CHANNEL_A] = 0;
289 peek_flag[SC16IS752_CHANNEL_B] = 0;
290 }
291
293 SC16IS752(SPIClass& spi, uint8_t ss_pin,
294 uint32_t crystal_freq_hz = SC16IS750_CRYSTCAL_FREQ)
295 : channel_a_stream(*this, SC16IS752_CHANNEL_A),
296 channel_b_stream(*this, SC16IS752_CHANNEL_B) {
297 device_address_sspin = ss_pin;
298 wire_bus = nullptr;
299 spi_bus = &spi;
300 crystal_freq = crystal_freq_hz;
301 timeout = 1000;
302 peek_buf[SC16IS752_CHANNEL_A] = -1;
303 peek_buf[SC16IS752_CHANNEL_B] = -1;
304 peek_flag[SC16IS752_CHANNEL_A] = 0;
305 peek_flag[SC16IS752_CHANNEL_B] = 0;
306 }
307
309 SC16IS752(const SC16IS752&) = delete;
311 SC16IS752& operator=(const SC16IS752&) = delete;
313 SC16IS752(SC16IS752&&) = delete;
316
318 ChannelStream& channelA() { return channel_a_stream; }
320 ChannelStream& channelB() { return channel_b_stream; }
321
323 void setLogger(SC16IS752Logger* log) { logger = log; }
325 void setTimeout(uint32_t time_out) { timeout = time_out; }
326
328 void end() {
331 resetDevice();
332 is_active = false;
333 }
334
335
336 friend class ChannelStream;
337
338 protected:
339 // General Registers
340 static constexpr uint8_t SC16IS750_REG_RHR =
341 0x00;
342 static constexpr uint8_t SC16IS750_REG_THR =
343 0x00;
344 static constexpr uint8_t SC16IS750_REG_IER =
345 0x01;
346 static constexpr uint8_t SC16IS750_REG_FCR =
347 0x02;
348 static constexpr uint8_t SC16IS750_REG_IIR =
349 0x02;
350 static constexpr uint8_t SC16IS750_REG_LCR =
351 0x03;
352 static constexpr uint8_t SC16IS750_REG_MCR =
353 0x04;
354 static constexpr uint8_t SC16IS750_REG_LSR = 0x05;
355 static constexpr uint8_t SC16IS750_REG_MSR =
356 0x06;
357 static constexpr uint8_t SC16IS750_REG_SPR = 0x07;
358 static constexpr uint8_t SC16IS750_REG_TCR =
359 0x06;
360 static constexpr uint8_t SC16IS750_REG_TLR =
361 0x07;
362 static constexpr uint8_t SC16IS750_REG_TXLVL =
363 0x08;
364 static constexpr uint8_t SC16IS750_REG_RXLVL =
365 0x09;
366 static constexpr uint8_t SC16IS750_REG_IODIR =
367 0x0A;
368 static constexpr uint8_t SC16IS750_REG_IOSTATE =
369 0x0B;
370 static constexpr uint8_t SC16IS750_REG_IOINTENA =
371 0x0C;
372 static constexpr uint8_t SC16IS750_REG_IOCONTROL =
373 0x0E;
374 static constexpr uint8_t SC16IS750_REG_EFCR =
375 0x0F;
376
377 // Special Registers
378 static constexpr uint8_t SC16IS750_REG_DLL = 0x00;
379 static constexpr uint8_t SC16IS750_REG_DLH = 0x01;
380
381 // Enhanced Registers
382 static constexpr uint8_t SC16IS750_REG_EFR =
383 0x02;
384 static constexpr uint8_t SC16IS750_REG_XON1 =
385 0x04;
386 static constexpr uint8_t SC16IS750_REG_XON2 =
387 0x05;
388 static constexpr uint8_t SC16IS750_REG_XOFF1 =
389 0x06;
390 static constexpr uint8_t SC16IS750_REG_XOFF2 =
391 0x07;
392
393 // Interrupt Enable Register
394 static constexpr uint8_t SC16IS750_INT_CTS =
395 0x80;
396 static constexpr uint8_t SC16IS750_INT_RTS =
397 0x40;
398 static constexpr uint8_t SC16IS750_INT_XOFF =
399 0x20;
400 static constexpr uint8_t SC16IS750_INT_SLEEP =
401 0x10;
402 static constexpr uint8_t SC16IS750_INT_MODEM =
403 0x08;
404 static constexpr uint8_t SC16IS750_INT_LINE =
405 0x04;
406 static constexpr uint8_t SC16IS750_INT_THR =
407 0x02;
408 static constexpr uint8_t SC16IS750_INT_RHR =
409 0x01;
410
411 // Application related
412 // static constexpr uint32_t SC16IS750_CRYSTCAL_FREQ = 14745600UL; ///<
413 // Optional crystal frequency (Hz).
414 static constexpr uint32_t SC16IS750_CRYSTCAL_FREQ =
415 1843200UL;
416 // static constexpr uint32_t SC16IS750_CRYSTCAL_FREQ = 16000000UL; ///<
417 // Optional crystal frequency (Hz).
418
419 bool is_active = false;
420 uint8_t device_address_sspin;
421 TwoWire* wire_bus;
422 SPIClass* spi_bus;
423 SPISettings spi_settings{SC16IS752_DEFAULT_SPI_CLOCK, MSBFIRST, SPI_MODE0};
424 uint32_t crystal_freq = SC16IS750_CRYSTCAL_FREQ;
425 uint32_t timeout;
426 ChannelStream channel_a_stream;
427 ChannelStream channel_b_stream;
428 int peek_buf[2];
429 uint8_t peek_flag[2];
430 SC16IS752Logger* logger = nullptr;
431
463 void beginChannel(SC16IS752_Channel channel, uint32_t baudrate,
464 uint32_t config = SC16IS752_DEFAULT_CONFIG) {
466 fifoEnable(channel, 1);
467 setBaudrate(channel, baudrate);
468 setLine(channel, config);
469 }
470
473 if (channel > SC16IS752_CHANNEL_B) {
474 return;
475 }
476 flush(channel);
477 fifoReset(channel, 0); // reset RX FIFO
478 fifoReset(channel, 1); // reset TX FIFO
479 fifoEnable(channel, 0);
480 }
481
483 int read(SC16IS752_Channel channel) {
484 if (channel > SC16IS752_CHANNEL_B) {
485 return -1;
486 }
487 if (peek_flag[channel] == 0) {
488 return readByte(channel);
489 } else {
490 peek_flag[channel] = 0;
491 return peek_buf[channel];
492 }
493 }
494
496 size_t write(SC16IS752_Channel channel, uint8_t val) {
497 writeByte(channel, val);
498 return 1;
499 }
500
503 return fifoAvailableData(channel);
504 }
505
507 uint8_t linestate(SC16IS752_Channel channel) {
508 return readRegister(channel, SC16IS750_REG_LSR);
509 }
511 uint8_t ping() {
514 return 0;
515 }
516
519 return 0;
520 }
521
524 return 0;
525 }
526
529 return 0;
530 }
531
532 return 1;
533 }
534
536 int peek(SC16IS752_Channel channel) {
537 if (channel > SC16IS752_CHANNEL_B) {
538 return -1;
539 }
540 if (peek_flag[channel] == 0) {
541 peek_buf[channel] = readByte(channel);
542 if (peek_buf[channel] >= 0) {
543 peek_flag[channel] = 1;
544 }
545 }
546
547 return peek_buf[channel];
548 }
549
551 void flush(SC16IS752_Channel channel) {
552 if (channel > SC16IS752_CHANNEL_B) {
553 return;
554 }
555
556 uint8_t tmp_lsr;
557 uint32_t start = millis();
558
559 do {
560 tmp_lsr = readRegister(channel, SC16IS750_REG_LSR);
561 if ((tmp_lsr & 0x20) != 0) {
562 return;
563 }
564 } while ((millis() - start) < timeout);
565
566 if (logger) {
567 logger->warn("flush timeout ch=%d", channel);
568 }
569 }
570
573 return (readRegister(channel, SC16IS750_REG_IIR) & 0x01);
574 }
575
578 uint8_t irq_src;
579
580 irq_src = readRegister(channel, SC16IS750_REG_IIR);
581 // irq_src = (irq_src >> 1);
582 // irq_src &= 0x3F;
583 irq_src &= 0x3E;
584
585 switch (irq_src) {
586 case 0x06: // Receiver Line Status Error
587 return SC16IS750_RECEIVE_LINE_STATUS_ERROR;
588 case 0x0c: // Receiver time-out interrupt
589 return SC16IS750_RECEIVE_TIMEOUT_INTERRUPT;
590 case 0x04: // RHR interrupt
591 return SC16IS750_RHR_INTERRUPT;
592 case 0x02: // THR interrupt
593 return SC16IS750_THR_INTERRUPT;
594 case 0x00: // modem interrupt;
595 return SC16IS750_MODEM_INTERRUPT;
596 case 0x30: // input pin change of state
597 return SC16IS750_INPUT_PIN_CHANGE_STATE;
598 case 0x10: // XOFF
599 return SC16IS750_RECEIVE_XOFF;
600 case 0x20: // CTS,RTS
601 return SC16IS750_CTS_RTS_CHANGE;
602 default:
603 return -1;
604 }
605 return -1;
606 }
607
609 void setPinInterrupt(uint8_t io_int_ena) {
611 return;
612 }
613
616 void enableRs485(SC16IS752_Channel channel, bool invert_rts) {
617 uint8_t temp_efcr;
618 temp_efcr = readRegister(channel, SC16IS750_REG_EFCR);
619 if (!invert_rts) {
620 temp_efcr |= 0x20;
621 } else {
622 temp_efcr |= 0x30;
623 }
624 writeRegister(channel, SC16IS750_REG_EFCR, temp_efcr);
625
626 return;
627 }
628
630 void enableTransmit(SC16IS752_Channel channel, uint8_t tx_enable) {
631 uint8_t temp_efcr;
632 temp_efcr = readRegister(channel, SC16IS750_REG_EFCR);
633 if (tx_enable == 0) {
634 temp_efcr |= 0x04;
635 } else {
636 temp_efcr &= 0xFB;
637 }
638 writeRegister(channel, SC16IS750_REG_EFCR, temp_efcr);
639
640 return;
641 }
642
645 if (!is_active) {
646 if (spi_bus != nullptr) {
647 pinMode(device_address_sspin, OUTPUT);
648 digitalWrite(device_address_sspin, HIGH);
649 }
650 resetDevice();
651 is_active = true;
652 }
653 }
654
659
661 void interruptControl(SC16IS752_Channel channel, uint8_t int_ena) {
662 writeRegister(channel, SC16IS750_REG_IER, int_ena);
663 }
664
666 void modemPin(uint8_t gpio) { // gpio == 0, gpio[7:4] are modem pins, gpio ==
667 // 1 gpio[7:4] are gpios
668 uint8_t temp_iocontrol;
669
670 temp_iocontrol =
672 if (gpio == 0) {
673 temp_iocontrol |= 0x02;
674 } else {
675 temp_iocontrol &= 0xFD;
676 }
678 temp_iocontrol);
679
680 return;
681 }
682
684 void gpioLatch(uint8_t latch) {
685 uint8_t temp_iocontrol;
686
687 temp_iocontrol =
689 if (latch == 0) {
690 temp_iocontrol &= 0xFE;
691 } else {
692 temp_iocontrol |= 0x01;
693 }
695 temp_iocontrol);
696
697 return;
698 }
699
701 int16_t setBaudrate(
702 SC16IS752_Channel channel,
703 uint32_t baudrate) { // return error of baudrate parts per thousand
704 uint16_t divisor;
705 uint8_t prescaler;
706 uint32_t actual_baudrate;
707 int16_t error;
708 uint8_t temp_lcr;
709 if ((readRegister(channel, SC16IS750_REG_MCR) & 0x80) ==
710 0) { // if prescaler==1
711 prescaler = 1;
712 } else {
713 prescaler = 4;
714 }
715
716 divisor = (crystal_freq / prescaler) / (baudrate * 16);
717
718 temp_lcr = readRegister(channel, SC16IS750_REG_LCR);
719 temp_lcr |= 0x80;
720 writeRegister(channel, SC16IS750_REG_LCR, temp_lcr);
721 // write to DLL
722 writeRegister(channel, SC16IS750_REG_DLL, (uint8_t)divisor);
723 // write to DLH
724 writeRegister(channel, SC16IS750_REG_DLH, (uint8_t)(divisor >> 8));
725 temp_lcr &= 0x7F;
726 writeRegister(channel, SC16IS750_REG_LCR, temp_lcr);
727
728 actual_baudrate = (crystal_freq / prescaler) / (16 * divisor);
729 error = ((float)actual_baudrate - baudrate) * 1000 / baudrate;
730 if (logger) {
731 logger->debug("Desired baudrate: %d", baudrate);
732 logger->debug("Calculated divisor: %d", divisor);
733 logger->debug("Actual baudrate: %d", actual_baudrate);
734 logger->debug("Baudrate error: %d", (int)error);
735 }
736
737 return error;
738 }
739
741 uint8_t readRegister(SC16IS752_Channel channel, uint8_t reg_addr) {
742 uint8_t result;
743 if (wire_bus != nullptr) { // register read operation via I2C
744 wire_bus->beginTransmission(device_address_sspin);
745 wire_bus->write((reg_addr << 3 | channel << 1));
746 wire_bus->endTransmission(0);
747 wire_bus->requestFrom(device_address_sspin, (uint8_t)1);
748 result = wire_bus->read();
749 } else if (spi_bus != nullptr) { // register read operation via SPI
750 spi_bus->beginTransaction(spi_settings);
751 ::digitalWrite(device_address_sspin, LOW);
752 delayMicroseconds(10);
753 spi_bus->transfer(0x80 | ((reg_addr << 3 | channel << 1)));
754 result = spi_bus->transfer(0xff);
755 delayMicroseconds(10);
756 ::digitalWrite(device_address_sspin, HIGH);
757 spi_bus->endTransaction();
758 } else {
759 result = 0;
760 }
761 if (logger) {
762 logger->debug("ReadRegister ch=%X reg=%X res=%X", channel,
763 (reg_addr << 3 | channel << 1), result);
764 }
765 return result;
766 }
767
769 void writeRegister(SC16IS752_Channel channel, uint8_t reg_addr, uint8_t val) {
770 if (logger) {
771 logger->debug("WriteRegister ch=%X reg=%X val=%X", channel,
772 (reg_addr << 3 | channel << 1), val);
773 }
774
775 if (wire_bus != nullptr) { // register write operation via I2C
776 wire_bus->beginTransmission(device_address_sspin);
777 wire_bus->write((reg_addr << 3 | channel << 1));
778 wire_bus->write(val);
779 wire_bus->endTransmission(1);
780 } else { // register write operation via SPI
781 spi_bus->beginTransaction(spi_settings);
782 ::digitalWrite(device_address_sspin, LOW);
783 delayMicroseconds(10);
784 spi_bus->transfer((reg_addr << 3 | channel << 1));
785 spi_bus->transfer(val);
786 delayMicroseconds(10);
787 ::digitalWrite(device_address_sspin, HIGH);
788 spi_bus->endTransaction();
789 }
790 return;
791 }
792
794 void setLine(SC16IS752_Channel channel, uint8_t data_length,
795 uint8_t parity_select, uint8_t stop_length) {
796 uint8_t temp_lcr;
797 temp_lcr = readRegister(channel, SC16IS750_REG_LCR);
798 temp_lcr &= 0xC0; // Clear the lower six bit of LCR (LCR[0] to LCR[5]
799 if (logger) {
800 logger->debug("LCR Register: %d", temp_lcr);
801 }
802 switch (data_length) { // data length settings
803 case 5:
804 break;
805 case 6:
806 temp_lcr |= 0x01;
807 break;
808 case 7:
809 temp_lcr |= 0x02;
810 break;
811 case 8:
812 temp_lcr |= 0x03;
813 break;
814 default:
815 temp_lcr |= 0x03;
816 break;
817 }
818
819 if (stop_length == 2) {
820 temp_lcr |= 0x04;
821 }
822
823 // parity selection length settings
824 switch (parity_select) {
825 case 0: // no parity
826 break;
827 case 1: // odd parity
828 temp_lcr |= 0x08;
829 break;
830 case 2: // even parity
831 temp_lcr |= 0x18;
832 break;
833 case 3: // force '1' parity
834 temp_lcr |= 0x03;
835 break;
836 case 4: // force '0' parity
837 break;
838 default:
839 break;
840 }
841
842 writeRegister(channel, SC16IS750_REG_LCR, temp_lcr);
843 }
844
846 void setLine(SC16IS752_Channel channel, uint32_t config) {
847 uint8_t data_length = 8;
848 uint8_t parity_select = 0;
849 uint8_t stop_length = 1;
850
851 if (!decodeSerialConfig(config, &data_length, &parity_select,
852 &stop_length)) {
853 if (logger) {
854 logger->warn("Unsupported serial config %lu, using SERIAL_8N1",
855 (unsigned long)config);
856 }
857 }
858
859 setLine(channel, data_length, parity_select, stop_length);
860 }
861
863 void pinMode(uint8_t pin, uint8_t io) { gpioSetPinMode(pin, io); }
864
866 void digitalWrite(uint8_t pin, uint8_t value) { gpioSetPinState(pin, value); }
867
869 uint8_t digitalRead(uint8_t pin) { return gpioGetPinState(pin); }
870
872 void gpioSetPinMode(uint8_t pin_number, uint8_t i_o) {
873 uint8_t temp_iodir;
874
876 if (i_o == OUTPUT) {
877 temp_iodir |= (0x01 << pin_number);
878 } else {
879 temp_iodir &= (uint8_t)~(0x01 << pin_number);
880 }
881
883 return;
884 }
885
887 void gpioSetPinState(uint8_t pin_number, uint8_t pin_state) {
888 uint8_t temp_iostate;
889
891 if (pin_state == 1) {
892 temp_iostate |= (0x01 << pin_number);
893 } else {
894 temp_iostate &= (uint8_t)~(0x01 << pin_number);
895 }
896
898 return;
899 }
900
902 uint8_t gpioGetPinState(uint8_t pin_number) {
903 uint8_t temp_iostate;
904
906 if ((temp_iostate & (0x01 << pin_number)) == 0) {
907 return 0;
908 }
909 return 1;
910 }
911
913 void gpioSetPortMode(uint8_t port_io) {
915 return;
916 }
917
919 void gpioSetPortState(uint8_t port_state) {
921 return;
922 }
923
925 void resetDevice() {
926 uint8_t reg;
927
929 reg |= 0x08;
931
932 return;
933 }
934
936 void fifoEnable(SC16IS752_Channel channel, uint8_t fifo_enable) {
937 uint8_t temp_fcr;
938
939 temp_fcr = readRegister(channel, SC16IS750_REG_FCR);
940
941 if (fifo_enable == 0) {
942 temp_fcr &= 0xFE;
943 } else {
944 temp_fcr |= 0x01;
945 }
946 writeRegister(channel, SC16IS750_REG_FCR, temp_fcr);
947
948 return;
949 }
950
952 void fifoReset(SC16IS752_Channel channel, uint8_t rx_fifo) {
953 uint8_t temp_fcr;
954
955 temp_fcr = readRegister(channel, SC16IS750_REG_FCR);
956
957 if (rx_fifo == 0) {
958 temp_fcr |= 0x04;
959 } else {
960 temp_fcr |= 0x02;
961 }
962 writeRegister(channel, SC16IS750_REG_FCR, temp_fcr);
963
964 return;
965 }
966
968 void fifoSetTriggerLevel(SC16IS752_Channel channel, uint8_t rx_fifo,
969 uint8_t length) {
970 uint8_t temp_reg;
971
972 temp_reg = readRegister(channel, SC16IS750_REG_MCR);
973 temp_reg |= 0x04;
975 temp_reg); // SET MCR[2] to '1' to use TLR register or
976 // trigger level control in FCR register
977
978 temp_reg = readRegister(channel, SC16IS750_REG_EFR);
980 channel, SC16IS750_REG_EFR,
981 temp_reg | 0x10); // set ERF[4] to '1' to use the enhanced features
982 if (rx_fifo == 0) {
984 length << 4); // Tx FIFO trigger level setting
985 } else {
987 length); // Rx FIFO Trigger level setting
988 }
990 temp_reg); // restore EFR register
991
992 return;
993 }
994
997 uint8_t avail = readRegister(channel, SC16IS750_REG_RXLVL);
998 if (logger) {
999 logger->debug("Available data: %d", avail);
1000 }
1001 return avail;
1002 }
1003
1006 return readRegister(channel, SC16IS750_REG_TXLVL);
1007 }
1008
1010 void writeByte(SC16IS752_Channel channel, uint8_t val) {
1011 uint8_t tmp_lsr;
1012
1013 do {
1014 tmp_lsr = readRegister(channel, SC16IS750_REG_LSR);
1015 } while ((tmp_lsr & 0x20) == 0);
1016
1017 writeRegister(channel, SC16IS750_REG_THR, val);
1018 }
1019
1022 volatile uint8_t val;
1023 if (fifoAvailableData(channel) == 0) {
1024 if (logger) {
1025 logger->debug("No data available");
1026 }
1027 return -1;
1028 } else {
1029 if (logger) {
1030 logger->debug("Data available");
1031 }
1032 val = readRegister(channel, SC16IS750_REG_RHR);
1033 return val;
1034 }
1035 }
1036
1038 bool decodeSerialConfig(uint32_t config, uint8_t* data_length,
1039 uint8_t* parity_select, uint8_t* stop_length) {
1040 switch (config) {
1041 case SERIAL_5N1:
1042 *data_length = 5;
1043 *parity_select = 0;
1044 *stop_length = 1;
1045 return true;
1046 case SERIAL_6N1:
1047 *data_length = 6;
1048 *parity_select = 0;
1049 *stop_length = 1;
1050 return true;
1051 case SERIAL_7N1:
1052 *data_length = 7;
1053 *parity_select = 0;
1054 *stop_length = 1;
1055 return true;
1056 case SERIAL_8N1:
1057 *data_length = 8;
1058 *parity_select = 0;
1059 *stop_length = 1;
1060 return true;
1061 case SERIAL_5N2:
1062 *data_length = 5;
1063 *parity_select = 0;
1064 *stop_length = 2;
1065 return true;
1066 case SERIAL_6N2:
1067 *data_length = 6;
1068 *parity_select = 0;
1069 *stop_length = 2;
1070 return true;
1071 case SERIAL_7N2:
1072 *data_length = 7;
1073 *parity_select = 0;
1074 *stop_length = 2;
1075 return true;
1076 case SERIAL_8N2:
1077 *data_length = 8;
1078 *parity_select = 0;
1079 *stop_length = 2;
1080 return true;
1081 case SERIAL_5E1:
1082 *data_length = 5;
1083 *parity_select = 2;
1084 *stop_length = 1;
1085 return true;
1086 case SERIAL_6E1:
1087 *data_length = 6;
1088 *parity_select = 2;
1089 *stop_length = 1;
1090 return true;
1091 case SERIAL_7E1:
1092 *data_length = 7;
1093 *parity_select = 2;
1094 *stop_length = 1;
1095 return true;
1096 case SERIAL_8E1:
1097 *data_length = 8;
1098 *parity_select = 2;
1099 *stop_length = 1;
1100 return true;
1101 case SERIAL_5E2:
1102 *data_length = 5;
1103 *parity_select = 2;
1104 *stop_length = 2;
1105 return true;
1106 case SERIAL_6E2:
1107 *data_length = 6;
1108 *parity_select = 2;
1109 *stop_length = 2;
1110 return true;
1111 case SERIAL_7E2:
1112 *data_length = 7;
1113 *parity_select = 2;
1114 *stop_length = 2;
1115 return true;
1116 case SERIAL_8E2:
1117 *data_length = 8;
1118 *parity_select = 2;
1119 *stop_length = 2;
1120 return true;
1121 case SERIAL_5O1:
1122 *data_length = 5;
1123 *parity_select = 1;
1124 *stop_length = 1;
1125 return true;
1126 case SERIAL_6O1:
1127 *data_length = 6;
1128 *parity_select = 1;
1129 *stop_length = 1;
1130 return true;
1131 case SERIAL_7O1:
1132 *data_length = 7;
1133 *parity_select = 1;
1134 *stop_length = 1;
1135 return true;
1136 case SERIAL_8O1:
1137 *data_length = 8;
1138 *parity_select = 1;
1139 *stop_length = 1;
1140 return true;
1141 case SERIAL_5O2:
1142 *data_length = 5;
1143 *parity_select = 1;
1144 *stop_length = 2;
1145 return true;
1146 case SERIAL_6O2:
1147 *data_length = 6;
1148 *parity_select = 1;
1149 *stop_length = 2;
1150 return true;
1151 case SERIAL_7O2:
1152 *data_length = 7;
1153 *parity_select = 1;
1154 *stop_length = 2;
1155 return true;
1156 case SERIAL_8O2:
1157 *data_length = 8;
1158 *parity_select = 1;
1159 *stop_length = 2;
1160 return true;
1161 default:
1162 *data_length = 8;
1163 *parity_select = 0;
1164 *stop_length = 1;
1165 return false;
1166 }
1167 }
1168};
1169
Simple logger for SC16IS752 channels with variadic parameter support and log levels.
Definition SC16IS752Logger.h:13
void warn(const char *format,...)
Log a formatted warning message.
Definition SC16IS752Logger.h:59
void debug(const char *format,...)
Log a formatted debug message.
Definition SC16IS752Logger.h:35
Per-channel Stream adapter for one SC16IS752 UART.
Definition SC16IS752.h:193
int read() override
Reads one byte from this channel.
Definition SC16IS752.h:203
void flush() override
Waits until pending transmission on this channel is complete.
Definition SC16IS752.h:207
uint8_t linestate()
Returns the line status register for this channel.
Definition SC16IS752.h:249
int available() override
Returns the number of bytes available for reading on this channel.
Definition SC16IS752.h:201
void interruptControl(uint8_t int_ena)
Controls interrupt enable bits for this channel.
Definition SC16IS752.h:267
void begin(uint32_t baudrate=SC16IS752_DEFAULT_SPEED, uint32_t config=SC16IS752_DEFAULT_CONFIG)
Initializes this channel with the specified baud rate and serial configuration.
Definition SC16IS752.h:242
void enableRs485(bool invert_rts)
Enables RS485 mode for this channel.
Definition SC16IS752.h:257
uint8_t interruptPendingTest()
Tests whether an interrupt is pending for this channel.
Definition SC16IS752.h:251
ChannelStream(SC16IS752 &parent, SC16IS752_Channel channel)
Creates a stream adapter bound to the selected UART channel.
Definition SC16IS752.h:196
void end()
Gracefully closes this channel.
Definition SC16IS752.h:247
void enableTransmit(uint8_t tx_enable)
Enables or disables transmission for this channel.
Definition SC16IS752.h:262
int peek() override
Peeks one byte from this channel without removing it.
Definition SC16IS752.h:205
size_t write(uint8_t val) override
Writes one byte to this channel.
Definition SC16IS752.h:209
int interruptEventTest()
Returns the decoded interrupt event for this channel.
Definition SC16IS752.h:255
Driver for the NXP SC16IS752 dual UART bridge over I2C or SPI.
Definition SC16IS752.h:170
static constexpr uint8_t SC16IS750_INT_RHR
RX holding register interrupt enable bit.
Definition SC16IS752.h:408
void setTimeout(uint32_t time_out)
Sets read timeout in milliseconds.
Definition SC16IS752.h:325
static constexpr uint8_t SC16IS750_REG_DLL
Divisor Latch LSB.
Definition SC16IS752.h:378
static constexpr uint8_t SC16IS750_REG_EFCR
Extra Features Control Register.
Definition SC16IS752.h:374
void flush(SC16IS752_Channel channel)
Waits for transmission to complete on the channel.
Definition SC16IS752.h:551
void setLogger(SC16IS752Logger *log)
Set logger for debug output.
Definition SC16IS752.h:323
void gpioSetPortState(uint8_t port_state)
Sets output state of all GPIO pins using a bitmask.
Definition SC16IS752.h:919
uint8_t gpioGetPinState(uint8_t pin_number)
Reads one GPIO pin state and returns 0 or 1.
Definition SC16IS752.h:902
static constexpr uint8_t SC16IS750_REG_IOSTATE
GPIO State Register.
Definition SC16IS752.h:368
SC16IS752(TwoWire &wire, uint8_t addr=SC16IS750_I2C_ADDRESS_AD, uint32_t crystal_freq_hz=SC16IS750_CRYSTCAL_FREQ)
Constructs an SC16IS752 instance using I2C transport.
Definition SC16IS752.h:277
uint8_t fifoAvailableSpace(SC16IS752_Channel channel)
Returns free space currently available in TX FIFO.
Definition SC16IS752.h:1005
static constexpr uint8_t SC16IS750_REG_XOFF1
XOFF1 flow-control character.
Definition SC16IS752.h:388
void gpioSetPortMode(uint8_t port_io)
Sets direction of all GPIO pins using a bitmask.
Definition SC16IS752.h:913
uint8_t ping()
Verifies device communication (returns 1 if successful)
Definition SC16IS752.h:511
static constexpr uint8_t SC16IS750_INT_SLEEP
Sleep mode interrupt enable bit.
Definition SC16IS752.h:400
void enableTransmit(SC16IS752_Channel channel, uint8_t tx_enable)
Enables or disables transmission on the specified channel.
Definition SC16IS752.h:630
uint8_t linestate(SC16IS752_Channel channel)
Returns line status register for the channel.
Definition SC16IS752.h:507
static constexpr uint8_t SC16IS750_REG_RXLVL
RX FIFO Level Register.
Definition SC16IS752.h:364
static constexpr uint8_t SC16IS750_REG_IIR
Interrupt Identification Register.
Definition SC16IS752.h:348
void setPinInterrupt(uint8_t io_int_ena)
Configures GPIO pin interrupt settings.
Definition SC16IS752.h:609
int read(SC16IS752_Channel channel)
Reads a byte from the specified channel.
Definition SC16IS752.h:483
uint8_t interruptPendingTest(SC16IS752_Channel channel)
Tests if an interrupt is pending on the channel.
Definition SC16IS752.h:572
static constexpr uint8_t SC16IS750_REG_LSR
Line Status Register.
Definition SC16IS752.h:354
void end()
Gracefully closes both UART channels and resets the device.
Definition SC16IS752.h:328
SC16IS752 & operator=(SC16IS752 &&)=delete
Prevent copying and moving of the driver instance.
bool decodeSerialConfig(uint32_t config, uint8_t *data_length, uint8_t *parity_select, uint8_t *stop_length)
Decodes Arduino SERIAL_* format into data bits, parity, and stop bits.
Definition SC16IS752.h:1038
static constexpr uint8_t SC16IS750_INT_RTS
RTS change interrupt enable bit.
Definition SC16IS752.h:396
static constexpr uint8_t SC16IS750_REG_EFR
Enhanced Features Register.
Definition SC16IS752.h:382
SC16IS752_Channel
UART channel selector used by channel-specific APIs.
Definition SC16IS752.h:176
@ SC16IS752_CHANNEL_A
UART channel A.
Definition SC16IS752.h:177
@ SC16IS752_CHANNEL_BOTH
Broadcast for global/shared registers.
Definition SC16IS752.h:179
@ SC16IS752_CHANNEL_B
UART channel B.
Definition SC16IS752.h:178
int interruptEventTest(SC16IS752_Channel channel)
Returns the type of interrupt event for the channel.
Definition SC16IS752.h:577
SC16IS752 & operator=(const SC16IS752 &)=delete
Prevent copying and moving of the driver instance.
static constexpr uint8_t SC16IS750_INT_THR
TX holding register interrupt enable bit.
Definition SC16IS752.h:406
static constexpr uint8_t SC16IS750_REG_TCR
Transmission Control Register.
Definition SC16IS752.h:358
int16_t setBaudrate(SC16IS752_Channel channel, uint32_t baudrate)
Configures baud rate divisor and returns error in parts-per-thousand.
Definition SC16IS752.h:701
static constexpr uint8_t SC16IS750_REG_TLR
Trigger Level Register.
Definition SC16IS752.h:360
static constexpr uint8_t SC16IS750_REG_IOCONTROL
GPIO/IO Control Register.
Definition SC16IS752.h:372
SC16IS752(SPIClass &spi, uint8_t ss_pin, uint32_t crystal_freq_hz=SC16IS750_CRYSTCAL_FREQ)
Constructs an SC16IS752 instance using SPI transport.
Definition SC16IS752.h:293
static constexpr uint8_t SC16IS750_REG_XON2
XON2 flow-control character.
Definition SC16IS752.h:386
static constexpr uint8_t SC16IS750_REG_IER
Interrupt Enable Register.
Definition SC16IS752.h:344
void gpioSetPinState(uint8_t pin_number, uint8_t pin_state)
Sets one GPIO output pin state (HIGH or LOW).
Definition SC16IS752.h:887
static constexpr uint8_t SC16IS750_REG_MSR
Modem Status Register.
Definition SC16IS752.h:355
static constexpr uint8_t SC16IS750_REG_FCR
FIFO Control Register.
Definition SC16IS752.h:346
static constexpr uint32_t SC16IS750_CRYSTCAL_FREQ
Default crystal frequency (Hz).
Definition SC16IS752.h:414
static constexpr uint8_t SC16IS750_REG_THR
Transmit Holding Register.
Definition SC16IS752.h:342
void fifoSetTriggerLevel(SC16IS752_Channel channel, uint8_t rx_fifo, uint8_t length)
Sets RX or TX FIFO trigger level for interrupt generation.
Definition SC16IS752.h:968
static constexpr uint8_t SC16IS750_INT_XOFF
XOFF interrupt enable bit.
Definition SC16IS752.h:398
void enableRs485(SC16IS752_Channel channel, bool invert_rts)
Definition SC16IS752.h:616
void gpioSetPinMode(uint8_t pin_number, uint8_t i_o)
Sets one GPIO pin direction (OUTPUT or INPUT).
Definition SC16IS752.h:872
ChannelStream & channelA()
Returns channel A stream adapter.
Definition SC16IS752.h:318
SC16IS752(SC16IS752 &&)=delete
Prevent copying and moving of the driver instance.
static constexpr uint8_t SC16IS750_REG_TXLVL
TX FIFO Level Register.
Definition SC16IS752.h:362
static constexpr uint8_t SC16IS750_REG_IODIR
GPIO Direction Register.
Definition SC16IS752.h:366
void writeByte(SC16IS752_Channel channel, uint8_t val)
Writes one byte to TX holding register when transmitter is ready.
Definition SC16IS752.h:1010
void interruptControl(SC16IS752_Channel channel, uint8_t int_ena)
Writes interrupt enable flags for the selected UART channel.
Definition SC16IS752.h:661
static constexpr uint8_t SC16IS750_INT_MODEM
Modem status interrupt enable bit.
Definition SC16IS752.h:402
static constexpr uint8_t SC16IS750_REG_XOFF2
XOFF2 flow-control character.
Definition SC16IS752.h:390
void fifoReset(SC16IS752_Channel channel, uint8_t rx_fifo)
Resets RX or TX FIFO for the selected channel.
Definition SC16IS752.h:952
static constexpr uint8_t SC16IS750_REG_DLH
Divisor Latch MSB.
Definition SC16IS752.h:379
void setLine(SC16IS752_Channel channel, uint32_t config)
Configures data bits, parity, and stop bits from an Arduino SERIAL_* value.
Definition SC16IS752.h:846
static constexpr uint8_t SC16IS750_REG_LCR
Line Control Register.
Definition SC16IS752.h:350
static constexpr uint8_t SC16IS750_REG_XON1
XON1 flow-control character.
Definition SC16IS752.h:384
void modemPin(uint8_t gpio)
Selects whether upper IO pins operate as modem pins or GPIO pins.
Definition SC16IS752.h:666
size_t write(SC16IS752_Channel channel, uint8_t val)
Writes a byte to the specified channel.
Definition SC16IS752.h:496
void fifoEnable(SC16IS752_Channel channel, uint8_t fifo_enable)
Enables or disables FIFO for the selected channel.
Definition SC16IS752.h:936
static constexpr uint8_t SC16IS750_INT_CTS
CTS change interrupt enable bit.
Definition SC16IS752.h:394
uint8_t digitalRead(uint8_t pin)
Reads GPIO pin level (returns 0 or 1)
Definition SC16IS752.h:869
int available(SC16IS752_Channel channel)
Returns number of bytes available to read from the channel.
Definition SC16IS752.h:502
void setLine(SC16IS752_Channel channel, uint8_t data_length, uint8_t parity_select, uint8_t stop_length)
Configures line format by data bits, parity mode, and stop bits.
Definition SC16IS752.h:794
ChannelStream & channelB()
Returns channel B stream adapter.
Definition SC16IS752.h:320
static constexpr uint8_t SC16IS750_REG_MCR
Modem Control Register.
Definition SC16IS752.h:352
void digitalWrite(uint8_t pin, uint8_t value)
Sets GPIO pin output level (HIGH or LOW)
Definition SC16IS752.h:866
void pinMode(uint8_t pin, uint8_t io)
Sets GPIO pin as input or output (OUTPUT or INPUT)
Definition SC16IS752.h:863
SC16IS752(const SC16IS752 &)=delete
Prevent copying and moving of the driver instance.
static constexpr uint8_t SC16IS750_REG_SPR
Scratchpad Register.
Definition SC16IS752.h:357
void endChannel(SC16IS752_Channel channel)
Gracefully closes a specific UART channel.
Definition SC16IS752.h:472
static constexpr uint8_t SC16IS750_REG_RHR
Receive Holding Register.
Definition SC16IS752.h:340
uint8_t gpioGetPortState(void)
Returns the current state of all GPIO pins as a bitmask.
Definition SC16IS752.h:656
static constexpr uint8_t SC16IS750_REG_IOINTENA
GPIO Interrupt Enable Register.
Definition SC16IS752.h:370
uint8_t fifoAvailableData(SC16IS752_Channel channel)
Returns number of bytes currently available in RX FIFO.
Definition SC16IS752.h:996
int readByte(SC16IS752_Channel channel)
Reads one byte from RX holding register, or -1 when no data is available.
Definition SC16IS752.h:1021
void writeRegister(SC16IS752_Channel channel, uint8_t reg_addr, uint8_t val)
Writes one register byte to the selected channel via I2C or SPI.
Definition SC16IS752.h:769
void initializeDevice()
Initializes the SC16IS752 device state on an already configured bus.
Definition SC16IS752.h:644
int peek(SC16IS752_Channel channel)
Reads a byte without removing it from the buffer.
Definition SC16IS752.h:536
void resetDevice()
Issues a software reset to the SC16IS752 device.
Definition SC16IS752.h:925
static constexpr uint8_t SC16IS750_INT_LINE
Line status interrupt enable bit.
Definition SC16IS752.h:404
uint8_t readRegister(SC16IS752_Channel channel, uint8_t reg_addr)
Reads one register byte from the selected channel via I2C or SPI.
Definition SC16IS752.h:741
void gpioLatch(uint8_t latch)
Enables or disables GPIO output latching behavior.
Definition SC16IS752.h:684
void beginChannel(SC16IS752_Channel channel, uint32_t baudrate, uint32_t config=SC16IS752_DEFAULT_CONFIG)
Initializes a specific UART channel with the given baud rate and serial configuration.
Definition SC16IS752.h:463