From 1f7c6c43019beaf4d9288e7d905c0b8ce8bfbc79 Mon Sep 17 00:00:00 2001 From: micooke Date: Tue, 17 Oct 2017 13:13:33 +1030 Subject: [PATCH 1/4] * Arduino.h : fix errors in #defines for digitalPinToPort, portOutputRegister, portModeRegister # WInterrupts * change attachInterrupt define to return the interrupt mask * callbacksInt, channelMap now uses an initialiser list instead of memset * GPIOTE_IRQn priority dropped from 1 to 3 (same as Uart priority) * LOW and HIGH modes added to attachInterrupt for compatibility, which are the same as FALLING and RISING respectively as GPIOTE does not support HIGH and LOW modes * To free up clock cycles between GPIOTE interrupts GPIOTE_IRQHandler now searches for the first GPIOTE event and breaks to execute, rather than staying in the interrupt and executing each GPIOTE callback that has triggered an interrupt. --- cores/nRF5/Arduino.h | 12 +++--- cores/nRF5/WInterrupts.c | 92 ++++++++++++++++++++++++++-------------- cores/nRF5/WInterrupts.h | 2 +- 3 files changed, 66 insertions(+), 40 deletions(-) diff --git a/cores/nRF5/Arduino.h b/cores/nRF5/Arduino.h index 39fbc0fe..bef516fb 100644 --- a/cores/nRF5/Arduino.h +++ b/cores/nRF5/Arduino.h @@ -29,11 +29,11 @@ extern "C"{ #define clockCyclesToMicroseconds(a) ( ((a) * 1000L) / (SystemCoreClock / 1000L) ) #define microsecondsToClockCycles(a) ( (a) * (SystemCoreClock / 1000000L) ) -void yield( void ) ; +void yield( void ); /* sketch */ -void setup( void ) ; -void loop( void ) ; +void setup( void ); +void loop( void ); #include "WVariant.h" @@ -92,12 +92,12 @@ void loop( void ) ; #define bit(b) (1UL << (b)) -#define digitalPinToPort(P) ( &(NRF_GPIO[P]) ) +#define digitalPinToPort(P) ( NRF_GPIO ) // NRF_P0 = P0.00 - P0.31, NRF_P1 = P1.00 - P1.15 (e.g. nRF52840) #define digitalPinToBitMask(P) ( 1 << g_ADigitalPinMap[P] ) //#define analogInPinToBit(P) ( ) -#define portOutputRegister(port) ( &(port->OUTSET) ) +#define portOutputRegister(port) ( &(port->OUT) ) #define portInputRegister(port) ( &(port->IN) ) -#define portModeRegister(port) ( &(port->DIRSET) ) +#define portModeRegister(port) ( &(port->DIR) ) #define digitalPinHasPWM(P) ( true ) /* diff --git a/cores/nRF5/WInterrupts.c b/cores/nRF5/WInterrupts.c index 59cc3cb4..5a9b8d1d 100644 --- a/cores/nRF5/WInterrupts.c +++ b/cores/nRF5/WInterrupts.c @@ -30,19 +30,16 @@ #define NUMBER_OF_GPIO_TE 4 #endif -static voidFuncPtr callbacksInt[NUMBER_OF_GPIO_TE]; -static int8_t channelMap[NUMBER_OF_GPIO_TE]; +static voidFuncPtr callbacksInt[NUMBER_OF_GPIO_TE] = { NULL }; +static int8_t channelMap[NUMBER_OF_GPIO_TE] = { -1 }; static int enabled = 0; /* Configure I/O interrupt sources */ static void __initialize() { - memset(callbacksInt, 0, sizeof(callbacksInt)); - memset(channelMap, -1, sizeof(channelMap)); - NVIC_DisableIRQ(GPIOTE_IRQn); NVIC_ClearPendingIRQ(GPIOTE_IRQn); - NVIC_SetPriority(GPIOTE_IRQn, 1); + NVIC_SetPriority(GPIOTE_IRQn, 3); // Same priority as Uart NVIC_EnableIRQ(GPIOTE_IRQn); } @@ -50,22 +47,29 @@ static void __initialize() * \brief Specifies a named Interrupt Service Routine (ISR) to call when an interrupt occurs. * Replaces any previous function that was attached to the interrupt. */ -void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode) +int attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode) { - if (!enabled) { - __initialize(); - enabled = 1; - } + uint32_t polarity; + uint8_t ch; - if (pin >= PINS_COUNT) { - return; + if (pin >= PINS_COUNT) + { + return -1; } pin = g_ADigitalPinMap[pin]; - uint32_t polarity; + switch (mode) + { + //gpiote channel does not support LOW and HIGH mode. These are mantained for compatibility + case LOW: + polarity = GPIOTE_CONFIG_POLARITY_HiToLo; //same as FALLING + break; + + case HIGH: + polarity = GPIOTE_CONFIG_POLARITY_LoToHi; //same as RISING + break; - switch (mode) { case CHANGE: polarity = GPIOTE_CONFIG_POLARITY_Toggle; break; @@ -79,11 +83,13 @@ void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode) break; default: - return; + return -1; } - for (int ch = 0; ch < NUMBER_OF_GPIO_TE; ch++) { - if (channelMap[ch] == -1 || (uint32_t)channelMap[ch] == pin) { + for (ch = 0; ch < NUMBER_OF_GPIO_TE; ch++) + { + if (channelMap[ch] == -1 || (uint32_t)channelMap[ch] == pin) + { channelMap[ch] = pin; callbacksInt[ch] = callback; @@ -98,6 +104,16 @@ void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode) break; } } + + // enable the interrupt after the first one is configured + if (!enabled) + { + __initialize(); + enabled = 1; + } + + // return the interrupt mask + return (1 << ch); } /* @@ -127,21 +143,31 @@ void detachInterrupt(uint32_t pin) void GPIOTE_IRQHandler() { - uint32_t event = offsetof(NRF_GPIOTE_Type, EVENTS_IN[0]); - - for (int ch = 0; ch < NUMBER_OF_GPIO_TE; ch++) { - if ((*(uint32_t *)((uint32_t)NRF_GPIOTE + event) == 0x1UL) && (NRF_GPIOTE->INTENSET & (1 << ch))) { - if (channelMap[ch] != -1 && callbacksInt[ch]) { - callbacksInt[ch](); - } - - *(uint32_t *)((uint32_t)NRF_GPIOTE + event) = 0; -#if __CORTEX_M == 0x04 - volatile uint32_t dummy = *((volatile uint32_t *)((uint32_t)NRF_GPIOTE + event)); - (void)dummy; -#endif + uint32_t event; + uint8_t ch; + + for (ch = 0; ch < NUMBER_OF_GPIO_TE; ch++) + { + event = offsetof(NRF_GPIOTE_Type, EVENTS_IN[ch]); + if ((*(uint32_t *)((uint32_t)NRF_GPIOTE + event) == 0x1UL) && (NRF_GPIOTE->INTENSET & (1 << ch))) + { + break; } - - event = (uint32_t)((uint32_t)event + 4); } + + // clear event + *(uint32_t *)((uint32_t)NRF_GPIOTE + event) = 0; + #if __CORTEX_M == 0x04 + volatile uint32_t dummy = *((volatile uint32_t *)((uint32_t)NRF_GPIOTE + event)); + (void)dummy; + #endif + + // disable the interrupt + NRF_GPIOTE->INTENCLR = (1 << ch); + + // initiate the callback + callbacksInt[ch](); + + // enable the interrupt + NRF_GPIOTE->INTENSET = (1 << ch); } diff --git a/cores/nRF5/WInterrupts.h b/cores/nRF5/WInterrupts.h index 5d2b24a0..61613f1e 100644 --- a/cores/nRF5/WInterrupts.h +++ b/cores/nRF5/WInterrupts.h @@ -40,7 +40,7 @@ typedef void (*voidFuncPtr)(void); * \brief Specifies a named Interrupt Service Routine (ISR) to call when an interrupt occurs. * Replaces any previous function that was attached to the interrupt. */ -void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode); +int attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode); /* * \brief Turns off the given interrupt. From 56a17f1555fad7eb9d5327e5356351460f607912 Mon Sep 17 00:00:00 2001 From: micooke Date: Wed, 25 Oct 2017 12:31:36 +1030 Subject: [PATCH 2/4] * Add SoftwareSerial library from @arduino-org arduino-core-nrf52 release 1.0.1 * merged SoftwareSerial.cpp into SoftwareSerial.h to allow ```_SS_MAX_RX_BUFF``` to be user-defined * added ```_SS_TX_ONLY``` user define to allow this to be used as a transmit only library (no interrupts used) * removed workarounds for legacy versions of Arduino that arent supported by this core --- libraries/SoftwareSerial/README.md | 30 ++ libraries/SoftwareSerial/SoftwareSerial.h | 471 ++++++++++++++++++ .../SoftwareSerialExample.ino | 38 ++ .../examples/TransmitOnly/TransmitOnly.ino | 36 ++ .../TwoPortReceive/TwoPortReceive.ino | 71 +++ libraries/SoftwareSerial/keywords.txt | 31 ++ libraries/SoftwareSerial/library.properties | 9 + 7 files changed, 686 insertions(+) create mode 100644 libraries/SoftwareSerial/README.md create mode 100644 libraries/SoftwareSerial/SoftwareSerial.h create mode 100644 libraries/SoftwareSerial/examples/SoftwareSerialExample/SoftwareSerialExample.ino create mode 100644 libraries/SoftwareSerial/examples/TransmitOnly/TransmitOnly.ino create mode 100644 libraries/SoftwareSerial/examples/TwoPortReceive/TwoPortReceive.ino create mode 100644 libraries/SoftwareSerial/keywords.txt create mode 100644 libraries/SoftwareSerial/library.properties diff --git a/libraries/SoftwareSerial/README.md b/libraries/SoftwareSerial/README.md new file mode 100644 index 00000000..218b7440 --- /dev/null +++ b/libraries/SoftwareSerial/README.md @@ -0,0 +1,30 @@ +### SoftwareSerial + +This library is based off SoftwareSerial from @arduino-org's arduino-core-nrf52 release [1.0.1](https://github.com/arduino-org/arduino-core-nrf52/releases/tag/1.0.1) + +#### Modifications +* merged SoftwareSerial.cpp into SoftwareSerial.h to allow ```_SS_MAX_RX_BUFF``` to be user-defined +* added ```_SS_TX_ONLY``` user define to allow this to be used as a transmit only library (no interrupts used) + +### License + +I do not claim copyright on the code, license taken from SoftwareSerial.h header. + +``` +SoftwareSerial.h - library for Arduino Primo +Copyright (c) 2016 Arduino. All rights reserved. + +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 St, Fifth Floor, Boston, MA 02110-1301 USA +``` \ No newline at end of file diff --git a/libraries/SoftwareSerial/SoftwareSerial.h b/libraries/SoftwareSerial/SoftwareSerial.h new file mode 100644 index 00000000..e166e55d --- /dev/null +++ b/libraries/SoftwareSerial/SoftwareSerial.h @@ -0,0 +1,471 @@ +/* + SoftwareSerial.h - library for Arduino Primo + Copyright (c) 2016 Arduino. All rights reserved. + + 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 St, Fifth Floor, Boston, MA 02110-1301 USA + + */ + +#ifndef SoftwareSerial_h +#define SoftwareSerial_h + +#include +#include +#include +#include +#include + +/****************************************************************************** +* Definitions +******************************************************************************/ + +#ifndef _SS_MAX_RX_BUFF +#define _SS_MAX_RX_BUFF 64 // RX buffer size +#endif + +#ifndef _SS_TX_ONLY +#define _SS_TX_ONLY 0 +#endif + +class SoftwareSerial : public Stream +{ + private: + // transmit data + uint8_t _transmitPin; + uint32_t _transmitBitMask; + volatile uint32_t* _transmitPortRegister; + + // Expressed as micro seconds + uint16_t _tx_delay_us; + +#if (_SS_TX_ONLY == 0) + // receive data + uint8_t _receivePin; + uint32_t _receiveBitMask; + volatile uint32_t* _receivePortRegister; + + volatile uint32_t _intMask; + + // Expressed as micro seconds + uint16_t _rx_delay_centering_us; + uint16_t _rx_delay_intrabit_us; + uint16_t _rx_delay_stopbit_us; + + uint16_t _buffer_overflow : 1; + + // static data + uint8_t _receive_buffer[_SS_MAX_RX_BUFF] = {0}; + volatile uint8_t _receive_buffer_tail; + volatile uint8_t _receive_buffer_head; + + static SoftwareSerial* active_object; +#endif + + uint16_t _inverse_logic : 1; + + // private methods + inline void recv() __attribute__((__always_inline__)); + uint32_t rx_pin_read(); + void tx_pin_write(uint8_t pin_state) __attribute__((__always_inline__)); + void setTX(uint8_t transmitPin); + void setRX(uint8_t receivePin); + void setRxIntMsk(bool enable) __attribute__((__always_inline__)); + + public: + // public methods + SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic = false); + ~SoftwareSerial(); + void begin(long speed); + bool listen(); + void end(); + bool isListening() + { +#if (_SS_TX_ONLY == 0) + return this == active_object; +#else + return 0; +#endif + } + bool stopListening(); + bool overflow() + { +#if (_SS_TX_ONLY == 0) + bool ret = _buffer_overflow; + if (ret) _buffer_overflow = false; + return ret; +#else + return 0; +#endif + } + int peek(); + + virtual size_t write(uint8_t byte); + virtual int read(); + virtual int available(); + virtual void flush(); + operator bool() { return true; } + + using Print::write; + + // public only for easy access by interrupt handlers + static inline void handle_interrupt() __attribute__((__always_inline__)); +}; + +#if (_SS_TX_ONLY == 0) +SoftwareSerial* SoftwareSerial::active_object = NULL; +#endif + +SoftwareSerial::SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, + bool inverse_logic /* = false */) + : +#if (_SS_TX_ONLY == 0) + _rx_delay_centering_us(0), + _rx_delay_intrabit_us(0), + _rx_delay_stopbit_us(0), + _buffer_overflow(false), + _intMask(0), + _receive_buffer_tail(0), + _receive_buffer_head(0), +#endif + _tx_delay_us(0), + _inverse_logic(inverse_logic) +{ +#if (_SS_TX_ONLY == 0) + _receivePin = receivePin; +#endif + _transmitPin = transmitPin; + + //_half_duplex = (_receivePin == _transmitPin) ? !_SS_TX_ONLY : 0; +} + +SoftwareSerial::~SoftwareSerial() { end(); } + +void SoftwareSerial::begin(long speed) +{ + setTX(_transmitPin); +#if (_SS_TX_ONLY == 0) + setRX(_receivePin); +#endif + + // Precalculate the various delays + // Calculate the distance between bit in micro seconds + uint32_t bit_delay = (float(1) / speed) * 1000000; + + _tx_delay_us = bit_delay; +#if (_SS_TX_ONLY == 0) + // Wait 1/2 bit - 2 micro seconds (time for interrupt to be served) + _rx_delay_centering_us = (bit_delay / 2) - 2; + // Wait 1 bit - 2 micro seconds (time in each loop iteration) + _rx_delay_intrabit_us = bit_delay - 1; // 2 + // Wait 1 bit (the stop one) + _rx_delay_stopbit_us = bit_delay; +#endif + delayMicroseconds(_tx_delay_us); + + listen(); +} + +bool SoftwareSerial::listen() +{ +#if (_SS_TX_ONLY == 0) + if (!_rx_delay_stopbit_us) return false; + + if (active_object != this) + { + if (active_object) active_object->stopListening(); + + _buffer_overflow = false; + _receive_buffer_head = _receive_buffer_tail = 0; + active_object = this; + + if (_inverse_logic) + { + // Start bit high + _intMask = attachInterrupt(_receivePin, handle_interrupt, RISING); + } + else + { + // Start bit low + _intMask = attachInterrupt(_receivePin, handle_interrupt, FALLING); + } + return true; + } +#endif + return false; +} + +bool SoftwareSerial::stopListening() +{ +#if (_SS_TX_ONLY == 0) + if (active_object == this) + { + detachInterrupt(_receivePin); + active_object = NULL; + return true; + } +#endif + return false; +} + +void SoftwareSerial::end() { stopListening(); } + +int SoftwareSerial::read() +{ +#if (_SS_TX_ONLY == 1) + this->println(F("read() is invalid - _SS_TX_ONLY is defined.")); +#else + if (isListening() == 0) + { + return -1; + } + + // Empty buffer? + if (_receive_buffer_head == _receive_buffer_tail) + { + return -1; + } + + // Read from "head" + uint8_t d = _receive_buffer[_receive_buffer_head]; // grab next byte + _receive_buffer_head = (_receive_buffer_head + 1) % _SS_MAX_RX_BUFF; + return d; +#endif +} + +int SoftwareSerial::available() +{ +#if (_SS_TX_ONLY == 0) + if (isListening() == 0) + return 0; + else + return (_receive_buffer_tail + _SS_MAX_RX_BUFF - _receive_buffer_head) % _SS_MAX_RX_BUFF; +#else + return 0; +#endif +} + +size_t SoftwareSerial::write(uint8_t b) +{ + if (_tx_delay_us == 0) + { + setWriteError(); + return 0; + } + + // By declaring these as local variables, the compiler will put them + // in registers _before_ disabling interrupts and entering the + // critical timing sections below, which makes it a lot easier to + // verify the cycle timings + volatile uint32_t* reg = _transmitPortRegister; + uint32_t reg_mask = _transmitBitMask; + uint32_t inv_mask = ~_transmitBitMask; + bool inv = _inverse_logic; + uint16_t delay = _tx_delay_us; + + if (inv) b = ~b; + +// turn off interrupts for a clean txmit +#ifndef _SS_TX_ONLY + NRF_GPIOTE->INTENCLR = _intMask; +#endif + + // Write the start bit + if (inv) + *reg |= reg_mask; + else + *reg &= inv_mask; + + delayMicroseconds(delay); + + // Write each of the 8 bits + for (uint8_t i = 8; i > 0; --i) + { + if (b & 1) // choose bit + *reg |= reg_mask; // send 1 + else + *reg &= inv_mask; // send 0 + + delayMicroseconds(delay); + b >>= 1; + } + + // restore pin to natural state + if (inv) + *reg &= inv_mask; + else + *reg |= reg_mask; + +// turn interrupts back on +#ifndef _SS_TX_ONLY + NRF_GPIOTE->INTENSET = _intMask; +#endif + + delayMicroseconds(delay); + + return 1; +} + +void SoftwareSerial::flush() +{ +#ifndef _SS_TX_ONLY + if (isListening() == 0) return; + + NRF_GPIOTE->INTENCLR = _intMask; + + _receive_buffer_head = _receive_buffer_tail = 0; + + NRF_GPIOTE->INTENSET = _intMask; +#endif +} + +int SoftwareSerial::peek() +{ +#ifdef _SS_TX_ONLY + return -1; +#else + if (isListening() == 0) return -1; + + // Empty buffer? + if (_receive_buffer_head == _receive_buffer_tail) return -1; + + // Read from "head" + return _receive_buffer[_receive_buffer_head]; +#endif +} + +// private methods + +inline void SoftwareSerial::recv() +{ +#if (_SS_TX_ONLY == 0) + uint8_t d = 0; + + // If RX line is high, then we don't see any start bit + // so interrupt is probably not for us + if (_inverse_logic ? rx_pin_read() : !rx_pin_read()) + { + NRF_GPIOTE->INTENCLR = _intMask; + + // Wait approximately 1/2 of a bit width to "center" the sample + delayMicroseconds(_rx_delay_centering_us); + + // Read each of the 8 bits + for (int8_t i = 8; i > 0; --i) + { + delayMicroseconds(_rx_delay_intrabit_us); + // nRF52 needs another delay less than 1 uSec to be better synchronized + // with the highest baud rates + __ASM volatile( + " NOP\n\t" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n" + " NOP\n"); + + d >>= 1; + + if (rx_pin_read()) + { + d |= 0x80; + } + } + if (_inverse_logic) + { + d = ~d; + } + + // if buffer full, set the overflow flag and return + uint8_t next = (_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF; + if (next != _receive_buffer_head) + { + // save new data in buffer: tail points to where byte goes + _receive_buffer[_receive_buffer_tail] = d; // save new byte + _receive_buffer_tail = next; + } + else + { + _buffer_overflow = true; + } + + // skip the stop bit + delayMicroseconds(_rx_delay_stopbit_us); + + NRF_GPIOTE->INTENSET = _intMask; + } +#endif +} + +uint32_t SoftwareSerial::rx_pin_read() +{ +#if (_SS_TX_ONLY == 0) + return *_receivePortRegister & digitalPinToBitMask(_receivePin); +#else + return 0; +#endif +} + +/* static */ +inline void SoftwareSerial::handle_interrupt() +{ +#if (_SS_TX_ONLY == 0) + if (active_object != NULL) + { + active_object->recv(); + } +#endif +} + +void SoftwareSerial::setTX(uint8_t tx) +{ + // First write, then set output. If we do this the other way around, + // the pin would be output low for a short while before switching to + // output high. Now, it is input with pullup for a short while, which + // is fine. With inverse logic, either order is fine. + _transmitPin = tx; + + digitalWrite(_transmitPin, _inverse_logic ? LOW : HIGH); + pinMode(_transmitPin, OUTPUT); + + _transmitBitMask = digitalPinToBitMask(_transmitPin); + NRF_GPIO_Type* port = digitalPinToPort(_transmitPin); + _transmitPortRegister = portOutputRegister(port); +} + +void SoftwareSerial::setRX(uint8_t rx) +{ +#if (_SS_TX_ONLY == 0) + _receivePin = rx; + + digitalWrite(_receivePin, _inverse_logic ? LOW : HIGH); + pinMode(_receivePin, INPUT); + + _receiveBitMask = digitalPinToBitMask(_receivePin); + NRF_GPIO_Type* port = digitalPinToPort(_receivePin); + _receivePortRegister = portInputRegister(port); +#endif +} + +#endif \ No newline at end of file diff --git a/libraries/SoftwareSerial/examples/SoftwareSerialExample/SoftwareSerialExample.ino b/libraries/SoftwareSerial/examples/SoftwareSerialExample/SoftwareSerialExample.ino new file mode 100644 index 00000000..4e179b7f --- /dev/null +++ b/libraries/SoftwareSerial/examples/SoftwareSerialExample/SoftwareSerialExample.ino @@ -0,0 +1,38 @@ +/* + Software serial multiple serial test + + Receives from the hardware serial, sends to software serial. + Receives from software serial, sends to hardware serial. + + The circuit: + * RX is digital pin 9 (connect to TX of other device) + * TX is digital pin 10 (connect to RX of other device) + + This example code is in the public domain. + + */ + +#include + +SoftwareSerial mySerial(9, 10); // RX, TX + + +void setup() +{ + // Open serial communications and wait for port to open: + Serial.begin(9600); + Serial.println("Goodnight moon!"); + + // set the data rate for the SoftwareSerial port + mySerial.begin(9600); + mySerial.println("Hello, world?"); +} + +void loop() // run over and over// +{ + if (mySerial.available()) + Serial.write(mySerial.read()); + + if (Serial.available()) + mySerial.write(Serial.read()); +} diff --git a/libraries/SoftwareSerial/examples/TransmitOnly/TransmitOnly.ino b/libraries/SoftwareSerial/examples/TransmitOnly/TransmitOnly.ino new file mode 100644 index 00000000..ca621ff7 --- /dev/null +++ b/libraries/SoftwareSerial/examples/TransmitOnly/TransmitOnly.ino @@ -0,0 +1,36 @@ +/* + SoftwareSerial TX Only test + + If your application is transmit only then setting + #define _SS_TX_ONLY 1 + Will stop the library allocating a GPIO interrupt and save 1364 bytes of memory + */ +#define _SS_TX_ONLY 1 +#include + +SoftwareSerial SoftSerial(2, 3); // RX, TX + +uint32_t t; +bool hb_state = false; // heartbeat + +void setup() +{ + pinMode(LED_BUILTIN, OUTPUT); + SoftSerial.begin(9600); + SoftSerial.println(__FILE__); + SoftSerial.println(__TIME__); + t = millis(); +} + +void loop() +{ + if (millis() - t > 1000) + { + t = millis(); + digitalWrite(LED_BUILTIN, hb_state); + hb_state = !hb_state; + SoftSerial.print("."); + } + + yield(); +} diff --git a/libraries/SoftwareSerial/examples/TwoPortReceive/TwoPortReceive.ino b/libraries/SoftwareSerial/examples/TwoPortReceive/TwoPortReceive.ino new file mode 100644 index 00000000..47d58091 --- /dev/null +++ b/libraries/SoftwareSerial/examples/TwoPortReceive/TwoPortReceive.ino @@ -0,0 +1,71 @@ +/* + Software serial multple serial test + + Receives from the two software serial ports, + sends to the hardware serial port. + + In order to listen on a software port, you call port.listen(). + When using two software serial ports, you have to switch ports + by listen()ing on each one in turn. Pick a logical time to switch + ports, like the end of an expected transmission, or when the + buffer is empty. This example switches ports when there is nothing + more to read from a port + + The circuit: + Two devices which communicate serially are needed. + * First serial device's TX attached to digital pin 9, RX to pin 11 + * Second serial device's TX attached to digital pin 8, RX to pin 10 + + This example code is in the public domain. + + */ + +#include +// software serial #1: TX = digital pin 11, RX = digital pin 9 +SoftwareSerial portOne(9, 11); + +// software serial #2: TX = digital pin 10, RX = digital pin 8 +SoftwareSerial portTwo(8, 10); + +void setup() +{ + // Open serial communications and wait for port to open: + Serial.begin(115200); + + // Start each software serial port + portOne.begin(9600); + portTwo.begin(9600); +} + +void loop() +{ + // By default, the last intialized port is listening. + // when you want to listen on a port, explicitly select it: + portOne.listen(); + + Serial.println("Data from port one:"); + // while there is data coming in, read it + // and send to the hardware serial port: + while (portOne.available() > 0) { + char inByte = portOne.read(); + Serial.write(inByte); + } + + // blank line to separate data from the two ports: + Serial.println(""); + + // Now listen on the second port + portTwo.listen(); + // while there is data coming in, read it + // and send to the hardware serial port: + + Serial.println("Data from port two:"); + while (portTwo.available() > 0) { + char inByte = portTwo.read(); + Serial.write(inByte); + } + + // blank line to separate data from the two ports: + Serial.println(); +} + diff --git a/libraries/SoftwareSerial/keywords.txt b/libraries/SoftwareSerial/keywords.txt new file mode 100644 index 00000000..e27a0cf4 --- /dev/null +++ b/libraries/SoftwareSerial/keywords.txt @@ -0,0 +1,31 @@ +####################################### +# Syntax Coloring Map for SoftwareSerial +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +SoftwareSerial KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +end KEYWORD2 +read KEYWORD2 +write KEYWORD2 +available KEYWORD2 +isListening KEYWORD2 +overflow KEYWORD2 +flush KEYWORD2 +listen KEYWORD2 +peek KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + +_SS_MAX_RX_BUFF LITERAL1 +_SS_TX_ONLY LITERAL1 \ No newline at end of file diff --git a/libraries/SoftwareSerial/library.properties b/libraries/SoftwareSerial/library.properties new file mode 100644 index 00000000..13a874dc --- /dev/null +++ b/libraries/SoftwareSerial/library.properties @@ -0,0 +1,9 @@ +name=SoftwareSerial +version=1.1.0 +author=Arduino +maintainer=Mark Cooke (https://github/micooke) +sentence=Enables serial communication on digital pins. +paragraph=The SoftwareSerial library has been developed to allow serial communication on any digital pin of the board, using software to replicate the functionality of the hardware UART. It is possible to have multiple software serial ports with speeds up to 115200 bps. +category=Communication +url=http://arduino.cc/en/Reference/SoftwareSerial +architectures=nrf52,nRF5 From f4ffcfaab900358f1f805bbe07b11041eb618829 Mon Sep 17 00:00:00 2001 From: Mark Cooke Date: Mon, 8 Jan 2018 12:15:20 +1030 Subject: [PATCH 3/4] * Bugfixes and corrections recommended by @carlosperate * Added separate LICENSE file * Updated Copyright information * Bugfix: replaced #ifdef / #ifndef _SS_TX_ONLY with #if _SS_TX_ONLY == 1/0 * Updated TransmitOnly.ino to demonstrate the use of _SS_MAX_RX_BUFF --- libraries/SoftwareSerial/LICENSE | 16 ++++++++++++++++ libraries/SoftwareSerial/README.md | 4 +--- libraries/SoftwareSerial/SoftwareSerial.h | 19 ++++++++++--------- .../examples/TransmitOnly/TransmitOnly.ino | 3 ++- libraries/SoftwareSerial/library.properties | 2 +- 5 files changed, 30 insertions(+), 14 deletions(-) create mode 100644 libraries/SoftwareSerial/LICENSE diff --git a/libraries/SoftwareSerial/LICENSE b/libraries/SoftwareSerial/LICENSE new file mode 100644 index 00000000..7574f55d --- /dev/null +++ b/libraries/SoftwareSerial/LICENSE @@ -0,0 +1,16 @@ +Copyright (c) 2016 Arduino. All rights reserved. +Copyright (c) 2017 Mark Cooke All right reserved. + +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 St, Fifth Floor, Boston, MA 02110-1301 USA \ No newline at end of file diff --git a/libraries/SoftwareSerial/README.md b/libraries/SoftwareSerial/README.md index 218b7440..00c34d81 100644 --- a/libraries/SoftwareSerial/README.md +++ b/libraries/SoftwareSerial/README.md @@ -8,11 +8,9 @@ This library is based off SoftwareSerial from @arduino-org's arduino-core-nrf52 ### License -I do not claim copyright on the code, license taken from SoftwareSerial.h header. - ``` -SoftwareSerial.h - library for Arduino Primo Copyright (c) 2016 Arduino. All rights reserved. +Copyright (c) 2017 Mark Cooke All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/libraries/SoftwareSerial/SoftwareSerial.h b/libraries/SoftwareSerial/SoftwareSerial.h index e166e55d..0642890c 100644 --- a/libraries/SoftwareSerial/SoftwareSerial.h +++ b/libraries/SoftwareSerial/SoftwareSerial.h @@ -1,21 +1,22 @@ /* - SoftwareSerial.h - library for Arduino Primo + SoftwareSerial.h - library for Nordic nRF5 devices + Copyright (c) 2016 Arduino. All rights reserved. - + Copyright (c) 2017 Mark Cooke All right reserved. + 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ #ifndef SoftwareSerial_h @@ -277,7 +278,7 @@ size_t SoftwareSerial::write(uint8_t b) if (inv) b = ~b; // turn off interrupts for a clean txmit -#ifndef _SS_TX_ONLY +#if (_SS_TX_ONLY == 0) NRF_GPIOTE->INTENCLR = _intMask; #endif @@ -308,7 +309,7 @@ size_t SoftwareSerial::write(uint8_t b) *reg |= reg_mask; // turn interrupts back on -#ifndef _SS_TX_ONLY +#if (_SS_TX_ONLY == 0) NRF_GPIOTE->INTENSET = _intMask; #endif @@ -319,7 +320,7 @@ size_t SoftwareSerial::write(uint8_t b) void SoftwareSerial::flush() { -#ifndef _SS_TX_ONLY +#if (_SS_TX_ONLY == 0) if (isListening() == 0) return; NRF_GPIOTE->INTENCLR = _intMask; @@ -332,7 +333,7 @@ void SoftwareSerial::flush() int SoftwareSerial::peek() { -#ifdef _SS_TX_ONLY +#if (_SS_TX_ONLY == 1) return -1; #else if (isListening() == 0) return -1; diff --git a/libraries/SoftwareSerial/examples/TransmitOnly/TransmitOnly.ino b/libraries/SoftwareSerial/examples/TransmitOnly/TransmitOnly.ino index ca621ff7..137b3427 100644 --- a/libraries/SoftwareSerial/examples/TransmitOnly/TransmitOnly.ino +++ b/libraries/SoftwareSerial/examples/TransmitOnly/TransmitOnly.ino @@ -5,7 +5,8 @@ #define _SS_TX_ONLY 1 Will stop the library allocating a GPIO interrupt and save 1364 bytes of memory */ -#define _SS_TX_ONLY 1 +#define _SS_TX_ONLY 1 // Transmit only (Rx pin is unused/unassigned, but still needs a number) +#define _SS_MAX_RX_BUFF 128 // Increase the Rx buffer to 128 bytes (default is 64 bytes) #include SoftwareSerial SoftSerial(2, 3); // RX, TX diff --git a/libraries/SoftwareSerial/library.properties b/libraries/SoftwareSerial/library.properties index 13a874dc..cb9b22bc 100644 --- a/libraries/SoftwareSerial/library.properties +++ b/libraries/SoftwareSerial/library.properties @@ -1,6 +1,6 @@ name=SoftwareSerial version=1.1.0 -author=Arduino +author=Arduino, Mark Cooke maintainer=Mark Cooke (https://github/micooke) sentence=Enables serial communication on digital pins. paragraph=The SoftwareSerial library has been developed to allow serial communication on any digital pin of the board, using software to replicate the functionality of the hardware UART. It is possible to have multiple software serial ports with speeds up to 115200 bps. From cee3d59ad91a96288e176443ebf8049040242d7d Mon Sep 17 00:00:00 2001 From: Mark Cooke Date: Tue, 9 Jan 2018 14:50:35 +1030 Subject: [PATCH 4/4] Update bytes saved number --- .../examples/TransmitOnly/TransmitOnly.ino | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/libraries/SoftwareSerial/examples/TransmitOnly/TransmitOnly.ino b/libraries/SoftwareSerial/examples/TransmitOnly/TransmitOnly.ino index 137b3427..1c6d6740 100644 --- a/libraries/SoftwareSerial/examples/TransmitOnly/TransmitOnly.ino +++ b/libraries/SoftwareSerial/examples/TransmitOnly/TransmitOnly.ino @@ -1,37 +1,37 @@ -/* - SoftwareSerial TX Only test - - If your application is transmit only then setting - #define _SS_TX_ONLY 1 - Will stop the library allocating a GPIO interrupt and save 1364 bytes of memory - */ -#define _SS_TX_ONLY 1 // Transmit only (Rx pin is unused/unassigned, but still needs a number) -#define _SS_MAX_RX_BUFF 128 // Increase the Rx buffer to 128 bytes (default is 64 bytes) -#include - -SoftwareSerial SoftSerial(2, 3); // RX, TX - -uint32_t t; -bool hb_state = false; // heartbeat - -void setup() -{ - pinMode(LED_BUILTIN, OUTPUT); - SoftSerial.begin(9600); - SoftSerial.println(__FILE__); - SoftSerial.println(__TIME__); - t = millis(); -} - -void loop() -{ - if (millis() - t > 1000) - { - t = millis(); - digitalWrite(LED_BUILTIN, hb_state); - hb_state = !hb_state; - SoftSerial.print("."); - } - - yield(); +/* + SoftwareSerial TX Only test + + If your application is transmit only then setting + #define _SS_TX_ONLY 1 + Will stop the library allocating a GPIO interrupt and save 1432 bytes of memory + */ +#define _SS_TX_ONLY 1 // Transmit only (Rx pin is unused/unassigned, but still needs a number) +#define _SS_MAX_RX_BUFF 128 // Increase the Rx buffer to 128 bytes (default is 64 bytes) +#include + +SoftwareSerial SoftSerial(2, 3); // RX, TX + +uint32_t t; +bool hb_state = false; // heartbeat + +void setup() +{ + pinMode(LED_BUILTIN, OUTPUT); + SoftSerial.begin(9600); + SoftSerial.println(__FILE__); + SoftSerial.println(__TIME__); + t = millis(); +} + +void loop() +{ + if (millis() - t > 1000) + { + t = millis(); + digitalWrite(LED_BUILTIN, hb_state); + hb_state = !hb_state; + SoftSerial.print("."); + } + + yield(); }