From 4f86b2a72a58d8323b7b25e8a37bcd459ca79657 Mon Sep 17 00:00:00 2001 From: DoDi Date: Sat, 28 May 2016 09:28:48 +0200 Subject: [PATCH 1/5] reorganize timer prescaling --- AltSoftSerial.cpp | 76 ++++++++++++++++++++++++++++------------------- AltSoftSerial.h | 11 +++---- 2 files changed, 51 insertions(+), 36 deletions(-) diff --git a/AltSoftSerial.cpp b/AltSoftSerial.cpp index 86061cc..b9a0fc7 100644 --- a/AltSoftSerial.cpp +++ b/AltSoftSerial.cpp @@ -1,17 +1,17 @@ /* 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 @@ -67,39 +67,53 @@ static volatile uint8_t tx_buffer[TX_BUFFER_SIZE]; #define MAX_COUNTS_PER_BIT 6241 // 65536 / 10.5 -void AltSoftSerial::init(uint32_t cycles_per_bit) +bool AltSoftSerial::prescale(uint32_t cycles_per_bit) { - //Serial.printf("cycles_per_bit = %d\n", cycles_per_bit); - if (cycles_per_bit < MAX_COUNTS_PER_BIT) { + timing_error = false; + ticks_per_bit = cycles_per_bit; + if (ticks_per_bit < MAX_COUNTS_PER_BIT) { + //Serial.printf("cycles_per_bit = %d\n", cycles_per_bit); CONFIG_TIMER_NOPRESCALE(); - } else { - cycles_per_bit /= 8; + return true; + } + ticks_per_bit = cycles_per_bit / 8; + if (ticks_per_bit < MAX_COUNTS_PER_BIT) { //Serial.printf("cycles_per_bit/8 = %d\n", cycles_per_bit); - if (cycles_per_bit < MAX_COUNTS_PER_BIT) { - CONFIG_TIMER_PRESCALE_8(); - } else { + CONFIG_TIMER_PRESCALE_8(); + return true; + } +#if defined(CONFIG_TIMER_PRESCALE_128) + ticks_per_bit = cycles_per_bit / 128; + if (ticks_per_bit < MAX_COUNTS_PER_BIT) { + //Serial.printf("cycles_per_bit/64 = %d\n", cycles_per_bit); + CONFIG_TIMER_PRESCALE_128(); + return true; + } +#endif #if defined(CONFIG_TIMER_PRESCALE_256) - cycles_per_bit /= 32; - //Serial.printf("cycles_per_bit/256 = %d\n", cycles_per_bit); - if (cycles_per_bit < MAX_COUNTS_PER_BIT) { - CONFIG_TIMER_PRESCALE_256(); - } else { - return; // baud rate too low for AltSoftSerial - } -#elif defined(CONFIG_TIMER_PRESCALE_128) - cycles_per_bit /= 16; - //Serial.printf("cycles_per_bit/128 = %d\n", cycles_per_bit); - if (cycles_per_bit < MAX_COUNTS_PER_BIT) { - CONFIG_TIMER_PRESCALE_128(); - } else { - return; // baud rate too low for AltSoftSerial - } -#else - return; // baud rate too low for AltSoftSerial + ticks_per_bit = cycles_per_bit / 256; + if (ticks_per_bit < MAX_COUNTS_PER_BIT) { + //Serial.printf("cycles_per_bit/256 = %d\n", cycles_per_bit); + CONFIG_TIMER_PRESCALE_256(); + return true; + } #endif - } +#if defined(CONFIG_TIMER_PRESCALE_1024) + ticks_per_bit = cycles_per_bit / 1024; + if (ticks_per_bit < MAX_COUNTS_PER_BIT) { + //Serial.printf("cycles_per_bit/1024 = %d\n", cycles_per_bit); + CONFIG_TIMER_PRESCALE_1024(); + return true; } - ticks_per_bit = cycles_per_bit; +#endif + timing_error = true; + //Serial.println("baudrate too low"); + return false; //baudrate too low +} + +bool AltSoftSerial::init(uint32_t cycles_per_bit) +{ + if (!prescale(cycles_per_bit)) return false; rx_stop_ticks = cycles_per_bit * 37 / 4; pinMode(INPUT_CAPTURE_PIN, INPUT_PULLUP); digitalWrite(OUTPUT_COMPARE_A_PIN, HIGH); @@ -111,6 +125,7 @@ void AltSoftSerial::init(uint32_t cycles_per_bit) tx_buffer_head = 0; tx_buffer_tail = 0; ENABLE_INT_INPUT_CAPTURE(); + return true; } void AltSoftSerial::end(void) @@ -347,4 +362,3 @@ void ftm0_isr(void) if (flags & (1<<6) && (FTM0_C6SC & 0x40)) altss_compare_a_interrupt(); } #endif - diff --git a/AltSoftSerial.h b/AltSoftSerial.h index eccb8d8..072fea4 100644 --- a/AltSoftSerial.h +++ b/AltSoftSerial.h @@ -1,17 +1,17 @@ /* 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 @@ -44,7 +44,7 @@ class AltSoftSerial : public Stream public: AltSoftSerial() { } ~AltSoftSerial() { end(); } - static void begin(uint32_t baud) { init((ALTSS_BASE_FREQ + baud / 2) / baud); } + static bool begin(uint32_t baud) { return init((ALTSS_BASE_FREQ + baud / 2) / baud); } static void end(); int peek(); int read(); @@ -68,8 +68,9 @@ class AltSoftSerial : public Stream static void enable_timer0(bool enable) { } static bool timing_error; private: - static void init(uint32_t cycles_per_bit); + static bool init(uint32_t cycles_per_bit); static void writeByte(uint8_t byte); + static bool prescale(uint32_t cycles_per_bit); }; #endif From 842f5f7b7cafa116934a4106c2a5534af2872d5f Mon Sep 17 00:00:00 2001 From: DoDi Date: Sat, 28 May 2016 10:12:10 +0200 Subject: [PATCH 2/5] prescale/1024 for T1-T5 --- config/AltSoftSerial_Timers.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/config/AltSoftSerial_Timers.h b/config/AltSoftSerial_Timers.h index 16df5b8..6962e78 100644 --- a/config/AltSoftSerial_Timers.h +++ b/config/AltSoftSerial_Timers.h @@ -1,17 +1,17 @@ /* 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 @@ -25,6 +25,7 @@ #define CONFIG_TIMER_NOPRESCALE() (TIMSK1 = 0, TCCR1A = 0, TCCR1B = (1< Date: Sat, 28 May 2016 10:54:54 +0200 Subject: [PATCH 3/5] add debug features for timing --- AltSoftSerial.cpp | 19 ++++++++++++++++++- AltSoftSerial.h | 3 +++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/AltSoftSerial.cpp b/AltSoftSerial.cpp index b9a0fc7..4a058df 100644 --- a/AltSoftSerial.cpp +++ b/AltSoftSerial.cpp @@ -40,6 +40,8 @@ /****************************************/ static uint16_t ticks_per_bit=0; +static uint16_t cycles_per_tick=0; +static uint16_t ticks_to_exit=16; bool AltSoftSerial::timing_error=false; static uint8_t rx_state; @@ -67,18 +69,29 @@ static volatile uint8_t tx_buffer[TX_BUFFER_SIZE]; #define MAX_COUNTS_PER_BIT 6241 // 65536 / 10.5 +uint16_t AltSoftSerial::ticksPerBit() +{ + return ticks_per_bit; +} +uint16_t AltSoftSerial::cyclesPerTick() +{ + return cycles_per_tick; +} + bool AltSoftSerial::prescale(uint32_t cycles_per_bit) { timing_error = false; ticks_per_bit = cycles_per_bit; if (ticks_per_bit < MAX_COUNTS_PER_BIT) { //Serial.printf("cycles_per_bit = %d\n", cycles_per_bit); + cycles_per_tick = 1; CONFIG_TIMER_NOPRESCALE(); return true; } ticks_per_bit = cycles_per_bit / 8; if (ticks_per_bit < MAX_COUNTS_PER_BIT) { //Serial.printf("cycles_per_bit/8 = %d\n", cycles_per_bit); + cycles_per_tick = 8; CONFIG_TIMER_PRESCALE_8(); return true; } @@ -86,6 +99,7 @@ bool AltSoftSerial::prescale(uint32_t cycles_per_bit) ticks_per_bit = cycles_per_bit / 128; if (ticks_per_bit < MAX_COUNTS_PER_BIT) { //Serial.printf("cycles_per_bit/64 = %d\n", cycles_per_bit); + cycles_per_tick = 128; CONFIG_TIMER_PRESCALE_128(); return true; } @@ -94,6 +108,7 @@ bool AltSoftSerial::prescale(uint32_t cycles_per_bit) ticks_per_bit = cycles_per_bit / 256; if (ticks_per_bit < MAX_COUNTS_PER_BIT) { //Serial.printf("cycles_per_bit/256 = %d\n", cycles_per_bit); + cycles_per_tick = 256; CONFIG_TIMER_PRESCALE_256(); return true; } @@ -102,6 +117,7 @@ bool AltSoftSerial::prescale(uint32_t cycles_per_bit) ticks_per_bit = cycles_per_bit / 1024; if (ticks_per_bit < MAX_COUNTS_PER_BIT) { //Serial.printf("cycles_per_bit/1024 = %d\n", cycles_per_bit); + cycles_per_tick = 1024; CONFIG_TIMER_PRESCALE_1024(); return true; } @@ -114,6 +130,7 @@ bool AltSoftSerial::prescale(uint32_t cycles_per_bit) bool AltSoftSerial::init(uint32_t cycles_per_bit) { if (!prescale(cycles_per_bit)) return false; + if (cycles_per_tick < 10) ticks_to_exit = 64; //TODO: adjust to meaningful minimum rx_stop_ticks = cycles_per_bit * 37 / 4; pinMode(INPUT_CAPTURE_PIN, INPUT_PULLUP); digitalWrite(OUTPUT_COMPARE_A_PIN, HIGH); @@ -218,7 +235,7 @@ ISR(COMPARE_A_INTERRUPT) if (state == 10) SET_COMPARE_A(target + ticks_per_bit); else - SET_COMPARE_A(GET_TIMER_COUNT() + 16); + SET_COMPARE_A(GET_TIMER_COUNT() + ticks_to_exit); tx_state = 1; // TODO: how to detect timing_error? } diff --git a/AltSoftSerial.h b/AltSoftSerial.h index 072fea4..b418697 100644 --- a/AltSoftSerial.h +++ b/AltSoftSerial.h @@ -67,6 +67,9 @@ class AltSoftSerial : public Stream static int library_version() { return 1; } static void enable_timer0(bool enable) { } static bool timing_error; + //debug features + static uint16_t ticksPerBit(); + static uint16_t cyclesPerTick(); private: static bool init(uint32_t cycles_per_bit); static void writeByte(uint8_t byte); From a1166bad955e05f6c690c49d83fb9cc9749a238d Mon Sep 17 00:00:00 2001 From: DoDi Date: Sat, 28 May 2016 11:03:19 +0200 Subject: [PATCH 4/5] improve delay before interrupt forced by interrupt allows for continuous sending @76800 baud (not 115k) --- AltSoftSerial.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AltSoftSerial.cpp b/AltSoftSerial.cpp index 4a058df..06d6afc 100644 --- a/AltSoftSerial.cpp +++ b/AltSoftSerial.cpp @@ -231,12 +231,12 @@ ISR(COMPARE_A_INTERRUPT) tx_buffer_tail = tail; tx_byte = tx_buffer[tail]; tx_bit = 0; + tx_state = 1; CONFIG_MATCH_CLEAR(); if (state == 10) SET_COMPARE_A(target + ticks_per_bit); else SET_COMPARE_A(GET_TIMER_COUNT() + ticks_to_exit); - tx_state = 1; // TODO: how to detect timing_error? } } From 936acfec32f2fdce71cda633c0f51457ae46cb29 Mon Sep 17 00:00:00 2001 From: DoDi Date: Sat, 28 May 2016 12:17:10 +0200 Subject: [PATCH 5/5] more flexible retrigger interval (works nearly for 115k, downto 300) --- AltSoftSerial.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/AltSoftSerial.cpp b/AltSoftSerial.cpp index 06d6afc..8a8aa4a 100644 --- a/AltSoftSerial.cpp +++ b/AltSoftSerial.cpp @@ -41,7 +41,7 @@ static uint16_t ticks_per_bit=0; static uint16_t cycles_per_tick=0; -static uint16_t ticks_to_exit=16; +static uint16_t ticks_to_exit=1; //if prescale > 8 bool AltSoftSerial::timing_error=false; static uint8_t rx_state; @@ -82,9 +82,11 @@ bool AltSoftSerial::prescale(uint32_t cycles_per_bit) { timing_error = false; ticks_per_bit = cycles_per_bit; + ticks_to_exit = 1; if (ticks_per_bit < MAX_COUNTS_PER_BIT) { //Serial.printf("cycles_per_bit = %d\n", cycles_per_bit); cycles_per_tick = 1; + ticks_to_exit = 64; CONFIG_TIMER_NOPRESCALE(); return true; } @@ -92,6 +94,7 @@ bool AltSoftSerial::prescale(uint32_t cycles_per_bit) if (ticks_per_bit < MAX_COUNTS_PER_BIT) { //Serial.printf("cycles_per_bit/8 = %d\n", cycles_per_bit); cycles_per_tick = 8; + ticks_to_exit = 8; CONFIG_TIMER_PRESCALE_8(); return true; } @@ -130,7 +133,6 @@ bool AltSoftSerial::prescale(uint32_t cycles_per_bit) bool AltSoftSerial::init(uint32_t cycles_per_bit) { if (!prescale(cycles_per_bit)) return false; - if (cycles_per_tick < 10) ticks_to_exit = 64; //TODO: adjust to meaningful minimum rx_stop_ticks = cycles_per_bit * 37 / 4; pinMode(INPUT_CAPTURE_PIN, INPUT_PULLUP); digitalWrite(OUTPUT_COMPARE_A_PIN, HIGH); @@ -206,10 +208,10 @@ ISR(COMPARE_A_INTERRUPT) } else { CONFIG_MATCH_CLEAR(); } - SET_COMPARE_A(target); tx_bit = bit; tx_byte = byte; tx_state = state; + SET_COMPARE_A(target); // TODO: how to detect timing_error? return; } @@ -220,7 +222,7 @@ ISR(COMPARE_A_INTERRUPT) if (state == 10) { // Wait for final stop bit to finish tx_state = 11; - SET_COMPARE_A(target + ticks_per_bit); + SET_COMPARE_A(target + ticks_per_bit + ticks_to_exit); } else { tx_state = 0; CONFIG_MATCH_NORMAL(); @@ -234,7 +236,7 @@ ISR(COMPARE_A_INTERRUPT) tx_state = 1; CONFIG_MATCH_CLEAR(); if (state == 10) - SET_COMPARE_A(target + ticks_per_bit); + SET_COMPARE_A(target + ticks_per_bit + ticks_to_exit); else SET_COMPARE_A(GET_TIMER_COUNT() + ticks_to_exit); // TODO: how to detect timing_error?