From 5577588df9d7b418ea3ccfbf9ae2721766e69345 Mon Sep 17 00:00:00 2001 From: remi Date: Wed, 25 Nov 2015 19:37:36 +0100 Subject: [PATCH] Add first version --- AltSoftSerial.cpp | 205 ++++++++++++++++++++++++++++++++++++++++++++++ AltSoftSerial.h | 111 +++++++++++++++++++++++++ README.md | 17 ++++ 3 files changed, 333 insertions(+) create mode 100644 AltSoftSerial.cpp create mode 100644 AltSoftSerial.h create mode 100644 README.md diff --git a/AltSoftSerial.cpp b/AltSoftSerial.cpp new file mode 100644 index 0000000..861bfc9 --- /dev/null +++ b/AltSoftSerial.cpp @@ -0,0 +1,205 @@ +/****************************************************************************** + * @file AltSoftSerial.h + * @author Rémi Pincent - INRIA + * @date 24 nov. 2015 + * + * @brief Bit-Banging uart + * + * Project : AltSoftSerial + * Contact: Rémi Pincent - remi.pincent@inria.fr + * + * Originally from + * + * LICENSE : + * AltSoftSerial (c) by Rémi Pincent + * AltSoftSerial is licensed under a + * Creative Commons Attribution-NonCommercial 3.0 Unported License. + * + * You should have received a copy of the license along with this + * work. If not, see . + * + * ORIGINALLY FROM : + * An Alternative Software Serial Library + * http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html + * Copyright (c) 2014 PJRC.COM, LLC, Paul Stoffregen, paul@pjrc.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + *****************************************************************************/ + +#include "AltSoftSerial.h" +#include "pinout.h" +extern "C"{ +#include "nrf_gpio.h" +#include "app_error.h" +} + +/****************************************/ +/** Defines **/ +/****************************************/ +#define UART_STOP_BIT_POS 8 +#define UART_STOP_BIT_ACTIVE 1 + +/****************************************/ +/** Variables **/ +/****************************************/ +AltSoftSerial AltSoftSerial::SoftSerial = AltSoftSerial(); + +/****************************************/ +/** Initialization **/ +/****************************************/ + +AltSoftSerial::AltSoftSerial() : _u8_txPin(INVALID_PIN), + _u16_ticks_per_bit(0), + _b_uartBusy(false), + timing_error(false), + _u8_sendByte(0), + _txBuffer(TX_BUFFER_SIZE) +{ + +} + +void AltSoftSerial::initTimer(void) +{ + /** Use TIMER 2 - Also used by Arduino Tone object */ + /** MUST not use TIMER0 : used by soft_device */ + NRF_TIMER2->MODE = TIMER_MODE_MODE_Timer; // Set the timer in Timer Mode. + NRF_TIMER2->PRESCALER = 0; // Prescaler 0 produces F_CPU/2^prescaler timer frequency => 1 tick = 32 us. + NRF_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_16Bit; // 16 bit mode + NRF_TIMER2->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Msk; // Short to lear IT + NRF_TIMER2->TASKS_CLEAR = 1; // clear the task first to be usable for later. + NRF_TIMER2->INTENSET = TIMER_INTENSET_COMPARE0_Msk; // Enable IT + NRF_TIMER2->CC[0] = _u16_ticks_per_bit; + + IntController_linkInterrupt( TIMER2_IRQn, AltSoftSerial::txTimerIRQ); + + if(!IntController_enableIRQ(TIMER2_IRQn, NRF_APP_PRIORITY_LOW)) + { + APP_ERROR_CHECK_BOOL(false); + } +} + +void AltSoftSerial::stopTimer(void) +{ + NRF_TIMER2->TASKS_STOP = 1; + NRF_TIMER2->INTENCLR = TIMER_INTENSET_COMPARE0_Disabled << TIMER_INTENCLR_COMPARE0_Pos; +} + +void AltSoftSerial::begin(uint32_t baud, uint8_t txPin) +{ + _u8_txPin = arduinoToVariantPin(txPin); + _u16_ticks_per_bit = F_CPU / baud; + + initTimer(); + pinMode(_u8_txPin, OUTPUT); + digitalWrite(txPin, HIGH); +} + +void AltSoftSerial::end(void) +{ + flushOutput(); + stopTimer(); +} + + +/****************************************/ +/** Transmission **/ +/****************************************/ + +bool AltSoftSerial::writeByte(uint8_t b) +{ + if(_txBuffer.pushElement(b) != RingBuffer::NO_ERROR) + { + /** May be buffer full... */ + return false; + } + + if (!_b_uartBusy) + { + _b_uartBusy = true; + _txBuffer.popElement(SoftSerial._u8_sendByte); + + // We set start bit active (low) + digitalWrite(_u8_txPin, LOW); + NRF_TIMER2->TASKS_START = 1; + } + else + { + /** UART busy but byte added to RING buffer */ + } + return true; +} + + +void AltSoftSerial::flushOutput(void) +{ + while (_b_uartBusy) /* wait */ ; +} + +/** + * Bit-Bang ring buffer bytes. No parity, start and stop bits, 8 bits + * + * ______________________________________________________________ + * | start bit | d0 | d1 | d2 | d3 | d4 | d5 | d6 | d7 | stop bit | + * |___________|____|____|____|____|____|____|____|____|__________| + * + */ +void AltSoftSerial::txTimerIRQ() +{ + if(NRF_TIMER2->EVENTS_COMPARE[0]) + { + static uint8_t bit_pos; + NRF_TIMER2->EVENTS_COMPARE[0] = 0; + + if (bit_pos < UART_STOP_BIT_POS) + { + /** set bit at bit_pos */ + (SoftSerial._u8_sendByte & (1 << bit_pos)) ? digitalWrite(SoftSerial._u8_txPin, HIGH) : digitalWrite(SoftSerial._u8_txPin, LOW);; + bit_pos++; + } + else if (bit_pos == UART_STOP_BIT_POS) + { + bit_pos++; + /** Set stop bit */ + digitalWrite(SoftSerial._u8_txPin, HIGH); + } + // We have to wait until STOP bit is finished before releasing m_uart_busy. + else if (bit_pos == UART_STOP_BIT_POS + 1) + { + bit_pos = 0; + if(!SoftSerial._txBuffer.elementsAvailable()) + { + /** no more byte to write to UART */ + NRF_TIMER2->TASKS_STOP = 1; + SoftSerial._b_uartBusy = false; + SoftSerial._u8_sendByte = 0; + return; + } + else + { + /** still some bytes to write to UART */ + SoftSerial._txBuffer.popElement(SoftSerial._u8_sendByte); + digitalWrite(SoftSerial._u8_txPin, LOW); + } + } + } +} + + + diff --git a/AltSoftSerial.h b/AltSoftSerial.h new file mode 100644 index 0000000..3e59229 --- /dev/null +++ b/AltSoftSerial.h @@ -0,0 +1,111 @@ +/****************************************************************************** + * @file AltSoftSerial.h + * @author Rémi Pincent - INRIA + * @date 24 nov. 2015 + * + * @brief Bit-Banging uart - Tx buffered + * + * Project : AltSoftSerial + * Contact: Rémi Pincent - remi.pincent@inria.fr + * + * Originally from + * + * LICENSE : + * AltSoftSerial (c) by Rémi Pincent + * AltSoftSerial is licensed under a + * Creative Commons Attribution-NonCommercial 3.0 Unported License. + * + * You should have received a copy of the license along with this + * work. If not, see . + * + * ORIGINALLY FROM : + * An Alternative Software Serial Library + * http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html + * Copyright (c) 2014 PJRC.COM, LLC, Paul Stoffregen, paul@pjrc.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + *****************************************************************************/ + +#ifndef AltSoftSerial_h +#define AltSoftSerial_h + +#include +#include + +#if ARDUINO >= 100 +#include "Arduino.h" +#else +#include "WProgram.h" +#include "pins_arduino.h" +#endif + +class AltSoftSerial : public Stream +{ +private : + static const uint8_t TX_BUFFER_SIZE = 40; + + uint8_t _u8_txPin; + uint16_t _u16_ticks_per_bit; + bool _b_uartBusy; + bool timing_error; + uint8_t _u8_sendByte; + RingBuffer _txBuffer; + +public: + /** instance */ + static AltSoftSerial SoftSerial; + +public: + AltSoftSerial(); + virtual ~AltSoftSerial() { end(); } + void begin(uint32_t baud, uint8_t txPin); + void end(); + /** RX not implemented */ + int peek(){return 0;}; + /** RX not implemented */ + int read(){return 0;}; + /** RX not implemented */ + int available(){return 0;}; +#if ARDUINO >= 100 + size_t write(uint8_t byte) { writeByte(byte); return 1; } + void flush() { flushOutput(); } +#else + void write(uint8_t byte) { writeByte(byte); } + void flush() { flushInput(); } +#endif + using Print::write; + /** RX not implemented */ + void flushInput(){return;}; + void flushOutput(); + // for drop-in compatibility with NewSoftSerial, rxPin & txPin ignored + AltSoftSerial(uint8_t rxPin, uint8_t txPin, bool inverse = false) : AltSoftSerial() { } + bool listen() { return false; } + bool isListening() { return true; } + bool overflow() { bool r = timing_error; timing_error = false; return r; } + static int library_version() { return 1; } + +private: + void initTimer(void); + void stopTimer(void); + bool writeByte(uint8_t byte); + static void txTimerIRQ(void); +}; + +#endif diff --git a/README.md b/README.md new file mode 100644 index 0000000..9bbfa7a --- /dev/null +++ b/README.md @@ -0,0 +1,17 @@ +# Description +Bit-banging UART + +# Supported platforms +* Nordic nrf51 + +## Limitations +* only tx Supported +* bad bit banging when Radio active, e.g when advertising. Timer used for bit banging has lower priority than BLE. + +# Code sample + + AltSoftSerial::SoftSerial.begin(9600, TX_PIN); + AltSoftSerial::SoftSerial.println("Hello from AltSoftSerial); + +# References +https://github.com/PaulStoffregen/AltSoftSerial \ No newline at end of file