diff --git a/.github/workflows/compile-examples.yml b/.github/workflows/compile-examples.yml index 0dc6b2b..93383bb 100644 --- a/.github/workflows/compile-examples.yml +++ b/.github/workflows/compile-examples.yml @@ -42,6 +42,11 @@ jobs: fqbn: arduino:mbed_portenta:envie_m7 platforms: | - name: arduino:mbed_portenta + libraries: | + - source-path: ./ + - name: ArduinoRS485 + sketch-paths: | + - examples enable-deltas-report: true enable-warnings-report: true sketches-report-path: ${{ env.SKETCHES_REPORTS_PATH }} diff --git a/examples/RS485_fullduplex/RS485_fullduplex.ino b/examples/RS485_fullduplex/RS485_fullduplex.ino index 67f772e..4c1a04a 100644 --- a/examples/RS485_fullduplex/RS485_fullduplex.ino +++ b/examples/RS485_fullduplex/RS485_fullduplex.ino @@ -2,7 +2,7 @@ RS485 Full duplex communication This sketch shows how to use the SP335ECR1 on the Machine - Control as a full duplex RS485 interface, how to periodically + Control as a full duplex (AB and YZ) RS485 interface, how to periodically send a string on the RS485 TX channel and how to receive data from the interface RX channel. @@ -10,6 +10,8 @@ - Portenta H7 - Machine Control - A Slave device with RS485 interface + - Connect TXP to A(+) and TXN to B(-) + - Connect RXP to Y(+) and RXN to Z(-) */ @@ -17,6 +19,8 @@ using namespace machinecontrol; +constexpr unsigned long sendInterval { 1000 }; +unsigned long sendNow { 0 }; unsigned long counter = 0; void setup() @@ -29,37 +33,47 @@ void setup() delay(1000); Serial.println("Start RS485 initialization"); - comm_protocols.rs485.begin(115200); - comm_protocols.rs485.enable = 1; // SDHN_N - comm_protocols.rs485.sel_485 = 1; // RS485_RS232_N - comm_protocols.rs485.half_duplex = 0; // HALF_FULL_N - comm_protocols.rs485.receive(); // RE_N - comm_protocols.rs485.fd_tx_term = 1; // FD_TX_TERM - 120 ohm Y-Z termination enabled when both TERM and FD_TX_TERM are high - comm_protocols.rs485.term = 1; // TERM - 120 ohm A-B termination enabled when high + // Set the PMC Communication Protocols to default config + comm_protocols.init(); + // RS485/RS232 default config is: + // - RS485 mode + // - Half Duplex + // - No A/B and Y/Z 120 Ohm termination enabled + + // Enable the RS485/RS232 system + comm_protocols.rs485Enable(true); + + // Enable Full Duplex mode + // This will also enable A/B and Y/Z 120 Ohm termination resistors + comm_protocols.rs485FullDuplex(true); + + // Specify baudrate, and preamble and postamble times for RS485 communication + comm_protocols.rs485.begin(115200, 0, 500); + + // Start in receive mode + comm_protocols.rs485.receive(); + Serial.println("Initialization done!"); } -constexpr unsigned long sendInterval { 1000 }; -unsigned long sendNow { 0 }; - -constexpr unsigned long halfFullInterval { 5000 }; -unsigned long halfFull { 0 }; -byte halfFullStatus { 0 }; - void loop() { - while (comm_protocols.rs485.available()) + if (comm_protocols.rs485.available()) Serial.write(comm_protocols.rs485.read()); if (millis() > sendNow) { + // Disable receive mode before transmission comm_protocols.rs485.noReceive(); + comm_protocols.rs485.beginTransmission(); comm_protocols.rs485.print("hello "); comm_protocols.rs485.println(counter++); comm_protocols.rs485.endTransmission(); + + // Re-enable receive mode after transmission comm_protocols.rs485.receive(); sendNow = millis() + sendInterval; diff --git a/examples/RS485_halfduplex/RS485_halfduplex.ino b/examples/RS485_halfduplex/RS485_halfduplex.ino new file mode 100644 index 0000000..3e5de9d --- /dev/null +++ b/examples/RS485_halfduplex/RS485_halfduplex.ino @@ -0,0 +1,77 @@ +/* + RS485 Half Duplex communication + + This sketch shows how to use the SP335ECR1 on the Machine + Control as a half duplex (AB) RS485 interface, how to periodically + send a string on the RS485 TX channel and how to receive data + from the interface RX channel. + + Circuit: + - Portenta H7 + - Machine Control + - A Slave device with RS485 interface + - Connect TXP to A(+) and TXN to B(-) + +*/ + +#include "Arduino_MachineControl.h" + +using namespace machinecontrol; + +constexpr unsigned long sendInterval { 1000 }; +unsigned long sendNow { 0 }; + +unsigned long counter { 0 }; + +void setup() +{ + + Serial.begin(115200); + // Wait for Serial or start after 2.5s + for (auto const timeout = millis() + 2500; !Serial && timeout < millis(); delay(500)) + ; + + delay(2500); + Serial.println("Start RS485 initialization"); + + // Set the PMC Communication Protocols to default config + comm_protocols.init(); + + // RS485/RS232 default config is: + // - RS485 mode + // - Half Duplex + // - No A/B and Y/Z 120 Ohm termination enabled + + // Enable the RS485/RS232 system + comm_protocols.rs485Enable(true); + + // Specify baudrate, and preamble and postamble times for RS485 communication + comm_protocols.rs485.begin(115200, 0, 500); + // Start in receive mode + comm_protocols.rs485.receive(); + + Serial.println("Initialization done!"); +} + +void loop() +{ + if (comm_protocols.rs485.available()) + Serial.write(comm_protocols.rs485.read()); + + if (millis() > sendNow) { + // Disable receive mode before transmission + comm_protocols.rs485.noReceive(); + + comm_protocols.rs485.beginTransmission(); + + comm_protocols.rs485.print("hello "); + comm_protocols.rs485.println(counter++); + + comm_protocols.rs485.endTransmission(); + + // Re-enable receive mode after transmission + comm_protocols.rs485.receive(); + + sendNow = millis() + sendInterval; + } +} diff --git a/library.properties b/library.properties index ec2190a..8f17bfe 100644 --- a/library.properties +++ b/library.properties @@ -8,3 +8,4 @@ category=Communication url=https://github.com/arduino-libraries/Arduino_MachineControl architectures=mbed, mbed_portenta includes=Arduino_MachineControl.h +depends=ArduinoRS485 diff --git a/src/Arduino_MachineControl.h b/src/Arduino_MachineControl.h index bfb8b0c..ca9798b 100644 --- a/src/Arduino_MachineControl.h +++ b/src/Arduino_MachineControl.h @@ -3,13 +3,14 @@ #include "utility/MAX31865/MAX31865.h" #include "utility/THERMOCOUPLE/MAX31855.h" -#include "utility/RS485/RS485.h" +#include #include "utility/QEI/QEI.h" #include "utility/ioexpander/ArduinoIOExpander.h" #include "utility/RTC/PCF8563T.h" #include "utility/RTC/PCF8563T.h" #include "Arduino.h" +#include "pinDefinitions.h" #include "mbed.h" #include "USBHost.h" @@ -57,11 +58,19 @@ class COMMClass { // to be tested: check if can be made a big pin initialization void init() { //SHUTDOWN OF RS485 LEDS - digitalWrite(PA_0, LOW); - digitalWrite(PI_9, LOW); + digitalWrite(PinNameToIndex(PA_0), LOW); + digitalWrite(PinNameToIndex(PI_9), LOW); //SHUTDOWN OF CAN LEDS - digitalWrite(PB_8, LOW); - digitalWrite(PH_13, LOW); + digitalWrite(PinNameToIndex(PB_8), LOW); + digitalWrite(PinNameToIndex(PH_13), LOW); + + // SET DEFAULTS for RS485 + rs485Enable(false); + rs485ModeRS232(false); + rs485FullDuplex(false); + rs485YZTerm(false); + rs485ABTerm(false); + rs485Slew(false); } void enableCAN() { @@ -74,11 +83,24 @@ class COMMClass { UART _UART4_ = arduino::UART(PA_0, PI_9, NC, NC); mbed::CAN& can = _can; - RS485Class rs485 = RS485Class(_UART4_,PA_0, PI_13,PI_10); + RS485Class rs485 = RS485Class(_UART4_, PinNameToIndex(PA_0), PinNameToIndex(PI_13), PinNameToIndex(PI_10)); + + void rs485Enable(bool enable) { digitalWrite(PinNameToIndex(PG_9), enable ? HIGH : LOW); } + void rs485ModeRS232(bool enable) { digitalWrite(PinNameToIndex(PA_10), enable ? LOW : HIGH); } + void rs485YZTerm(bool enable) { digitalWrite(PinNameToIndex(PI_15), enable ? HIGH : LOW); } + void rs485ABTerm(bool enable) { digitalWrite(PinNameToIndex(PI_14), enable ? HIGH : LOW); } + void rs485Slew(bool enable) { digitalWrite(PinNameToIndex(PG_14), enable ? LOW : HIGH); } + void rs485FullDuplex(bool enable) { + digitalWrite(PinNameToIndex(PA_9), enable ? LOW : HIGH); + if (enable) { + // RS485 Full Duplex require YZ and AB 120 Ohm termination enabled + rs485YZTerm(true); + rs485ABTerm(true); + } + } + private: mbed::DigitalOut can_disable = mbed::DigitalOut(PA_13, 0); - - }; extern COMMClass comm_protocols; diff --git a/src/utility/RS485/RS485.cpp b/src/utility/RS485/RS485.cpp deleted file mode 100644 index 5b544ad..0000000 --- a/src/utility/RS485/RS485.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/* - This file is part of the ArduinoRS485 library. - Copyright (c) 2020 Arduino SA. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include "RS485.h" - -RS485Class::RS485Class(HardwareSerial& hwSerial, PinName txPin, PinName dePin, PinName rePin) : - _serial(&hwSerial), - _txPin(txPin), - _dePin(dePin), - _rePin(rePin), - _transmisionBegun(false) -{ -} - -void RS485Class::begin(unsigned long baudrate) -{ - begin(baudrate, SERIAL_8N1); -} - -void RS485Class::begin(unsigned long baudrate, uint16_t config) -{ - _baudrate = baudrate; - _config = config; - - if (_dePin != NC) { - pinMode(_dePin, OUTPUT); - digitalWrite(_dePin, LOW); - } - - if (_rePin != NC) { - pinMode(_rePin, OUTPUT); - digitalWrite(_rePin, HIGH); - } - - _transmisionBegun = false; - - half_duplex.output(); - - _serial->begin(baudrate, config); -} - -void RS485Class::end() -{ - _serial->end(); - - if (_rePin != NC) { - digitalWrite(_rePin, LOW); - pinMode(_dePin, INPUT); - } - - if (_dePin != NC) { - digitalWrite(_dePin, LOW); - pinMode(_rePin, INPUT); - } -} - -int RS485Class::available() -{ - return _serial->available(); -} - -int RS485Class::peek() -{ - return _serial->peek(); -} - -int RS485Class::read(void) -{ - return _serial->read(); -} - -size_t RS485Class::readBytes(char *buf, size_t length) -{ - return _serial->readBytes(buf, length); -} - -void RS485Class::flush() -{ - return _serial->flush(); -} - -size_t RS485Class::write(uint8_t b) -{ - if (!_transmisionBegun) { - setWriteError(); - return 0; - } - - return _serial->write(b); -} - -RS485Class::operator bool() -{ - return true; -} - -void RS485Class::beginTransmission() -{ - if (_dePin > -1) { - digitalWrite(_dePin, HIGH); - delayMicroseconds(50); - } - - _transmisionBegun = true; -} - -void RS485Class::endTransmission() -{ - _serial->flush(); - - if (_dePin != NC) { - delayMicroseconds(500); - digitalWrite(_dePin, LOW); - } - - _transmisionBegun = false; -} - -void RS485Class::receive() -{ - if (_rePin != NC) { - digitalWrite(_rePin, LOW); - } -} - -void RS485Class::noReceive() -{ - if (_rePin != NC) { - digitalWrite(_rePin, HIGH); - } -} - -void RS485Class::sendBreak(unsigned int duration) -{ - _serial->flush(); - _serial->end(); - if (_txPin != NC) { - pinMode(_txPin, OUTPUT); - digitalWrite(_txPin, LOW); - } - delay(duration); - _serial->begin(_baudrate, _config); -} - -void RS485Class::sendBreakMicroseconds(unsigned int duration) -{ - _serial->flush(); - _serial->end(); - if (_txPin != NC) { - pinMode(_txPin, OUTPUT); - digitalWrite(_txPin, LOW); - } - delayMicroseconds(duration); - _serial->begin(_baudrate, _config); -} - -void RS485Class::setPins(PinName txPin, PinName dePin, PinName rePin) -{ - _txPin = txPin; - _dePin = dePin; - _rePin = rePin; -} diff --git a/src/utility/RS485/RS485.h b/src/utility/RS485/RS485.h deleted file mode 100644 index dbe8eea..0000000 --- a/src/utility/RS485/RS485.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - This file is part of the ArduinoRS485 library. - Copyright (c) 2020 Arduino SA. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _RS485_MACHINECONTROL_H_INCLUDED -#define _RS485_MACHINECONTROL_H_INCLUDED - -#include "Arduino.h" -#include "mbed.h" - -class RS485Class : public HardwareSerial { - public: - RS485Class(HardwareSerial& hwSerial, PinName txPin = NC, PinName dePin = NC, PinName rePin = NC); - - virtual void begin(unsigned long baudrate); - virtual void begin(unsigned long baudrate, uint16_t config); - virtual void end(); - virtual int available(); - virtual int peek(); - virtual int read(void); - virtual size_t readBytes(char *buf, size_t length); - virtual size_t readBytes(uint8_t *buf, size_t length) { return readBytes((char *)buf, length); }; - virtual void flush(); - virtual size_t write(uint8_t b); - using Print::write; // pull in write(str) and write(buf, size) from Print - virtual operator bool(); - - void beginTransmission(); - void endTransmission(); - void receive(); - void noReceive(); - - void sendBreak(unsigned int duration); - void sendBreakMicroseconds(unsigned int duration); - - void setPins(PinName txPin, PinName dePin, PinName rePin); - - mbed::DigitalInOut half_duplex = mbed::DigitalInOut(PA_9); - mbed::DigitalOut sel_485 = mbed::DigitalOut(PA_10); - mbed::DigitalOut slew_n = mbed::DigitalOut(PG_14); - mbed::DigitalOut fd_tx_term = mbed::DigitalOut(PI_15); - mbed::DigitalOut term = mbed::DigitalOut(PI_14); - mbed::DigitalOut enable = mbed::DigitalOut(PG_9); - - private: - HardwareSerial* _serial; - PinName _txPin; - PinName _dePin = NC; - PinName _rePin = NC; - - - bool _transmisionBegun; - unsigned long _baudrate; - uint16_t _config; -}; - -#endif