diff --git a/AstroEQ-ConfigUtility/hex/AstroEQATMega162Based(Legacy).hex b/AstroEQ-ConfigUtility/hex/AstroEQATMega162Based(Legacy).hex index 927c242cb3c7e861b09480f21f86698687bc1a6e..21bfd9a40eaedb1542a45cb20107300c55cb250d 100644 Binary files a/AstroEQ-ConfigUtility/hex/AstroEQATMega162Based(Legacy).hex and b/AstroEQ-ConfigUtility/hex/AstroEQATMega162Based(Legacy).hex differ diff --git a/AstroEQ-ConfigUtility/hex/AstroEQArduinoMega1280(Legacy).hex b/AstroEQ-ConfigUtility/hex/AstroEQArduinoMega1280(Legacy).hex index 895673397d5081bc0660615f974f02b6eae609f0..ab805ea8f1a1288a922e97052757517482ce02d0 100644 Binary files a/AstroEQ-ConfigUtility/hex/AstroEQArduinoMega1280(Legacy).hex and b/AstroEQ-ConfigUtility/hex/AstroEQArduinoMega1280(Legacy).hex differ diff --git a/AstroEQ-ConfigUtility/hex/AstroEQArduinoMega2560(Legacy).hex b/AstroEQ-ConfigUtility/hex/AstroEQArduinoMega2560(Legacy).hex index d39e268e140895ad3e3ce1e44de744e0c078d78d..f1d4060f99ed224defc1076c96fba5e0d819c1bf 100644 Binary files a/AstroEQ-ConfigUtility/hex/AstroEQArduinoMega2560(Legacy).hex and b/AstroEQ-ConfigUtility/hex/AstroEQArduinoMega2560(Legacy).hex differ diff --git a/AstroEQ-ConfigUtility/hex/AstroEQV4-DIYBoard(includingKits).hex b/AstroEQ-ConfigUtility/hex/AstroEQV4-DIYBoard(includingKits).hex index 569fcdc4cd949740bb827bd8367f7f724dcdfba5..54ab1d1831cc9065572d3f6a84df62dbf63dc198 100644 Binary files a/AstroEQ-ConfigUtility/hex/AstroEQV4-DIYBoard(includingKits).hex and b/AstroEQ-ConfigUtility/hex/AstroEQV4-DIYBoard(includingKits).hex differ diff --git a/AstroEQ-ConfigUtility/hex/AstroEQV4-EQ5Board.hex b/AstroEQ-ConfigUtility/hex/AstroEQV4-EQ5Board.hex index 569fcdc4cd949740bb827bd8367f7f724dcdfba5..54ab1d1831cc9065572d3f6a84df62dbf63dc198 100644 Binary files a/AstroEQ-ConfigUtility/hex/AstroEQV4-EQ5Board.hex and b/AstroEQ-ConfigUtility/hex/AstroEQV4-EQ5Board.hex differ diff --git a/AstroEQ-ConfigUtility/hex/hexNames.txt b/AstroEQ-ConfigUtility/hex/hexNames.txt index 183619299eb5be5596e071c36826f9925a90ea71..a766f48b6e554bcf49c57a4829cd4cb343925567 100644 --- a/AstroEQ-ConfigUtility/hex/hexNames.txt +++ b/AstroEQ-ConfigUtility/hex/hexNames.txt @@ -1,8 +1,8 @@ -AstroEQArduinoMega1280(Legacy) 6.5 -AstroEQArduinoMega2560(Legacy) 6.5 -AstroEQATMega162Based(Legacy) 6.5 -AstroEQV4-EQ5Board 6.5 -AstroEQV4-DIYBoard(includingKits) 6.5 +AstroEQArduinoMega1280(Legacy) 6.7 +AstroEQArduinoMega2560(Legacy) 6.7 +AstroEQATMega162Based(Legacy) 6.7 +AstroEQV4-EQ5Board 6.7 +AstroEQV4-DIYBoard(includingKits) 6.7 AstroEQArduinoMega1280(Legacy)EEPROMReader 1.2 AstroEQArduinoMega2560(Legacy)EEPROMReader 1.2 AstroEQATMega162Based(Legacy)EEPROMReader 1.2 diff --git a/AstroEQ-Firmware/AstroEQ6.ino b/AstroEQ-Firmware/AstroEQ6.ino index 77a205894deffcc2931814bf69cc9efbb7f666e1..0391101b0cfc3f9378bb4f71f09547aa0c34ab21 100644 --- a/AstroEQ-Firmware/AstroEQ6.ino +++ b/AstroEQ-Firmware/AstroEQ6.ino @@ -9,7 +9,7 @@ Works with EQ5, HEQ5, and EQ6 mounts - Current Verison: 6.5 + Current Verison: 6.7 */ //Only works with ATmega162, and Arduino Mega boards (1280 and 2560) @@ -145,8 +145,8 @@ void systemInitialiser(){ if(!checkEEPROM()){ while(1); //prevent AstroEQ startup if EEPROM is blank. } - minSpeed[RA] = synta.cmd.siderealIVal[RA]+1;//+(synta.cmd.siderealIVal[RA]>>4); - minSpeed[DC] = synta.cmd.siderealIVal[DC]+1;//+(synta.cmd.siderealIVal[DC]>>4); + minSpeed[RA] = synta.cmd.siderealIVal[RA]>>1;//2x sidereal rate. + minSpeed[DC] = synta.cmd.siderealIVal[DC]>>1;//[minspeed is the point at which acceleration curves are enabled] calculateRate(RA); //Initialise the interrupt speed table. This now only has to be done once at the beginning. calculateRate(DC); //Initialise the interrupt speed table. This now only has to be done once at the beginning. gotoDecelerationLength[RA] = calculateDecelerationLength(RA); @@ -198,20 +198,10 @@ int main(void) pinMode(modePin[j],OUTPUT); digitalWrite(modePin[j],state[j]); } -// pinMode(modePins[i][0],OUTPUT); //enable the mode pins -// pinMode(modePins[i][1],OUTPUT); //enable the mode pins -// digitalWrite(modePins[i][0],modeState[highSpeed[i]][0]); -// digitalWrite(modePins[i][1],modeState[highSpeed[i]][1]); #else for(byte j = 0; j < 3; j++){ pinMode(modePin[j],OUTPUT); digitalWrite(modePin[j],state[j]); -// pinMode(modePins[i][0],OUTPUT); //enable the mode pins -// pinMode(modePins[i][1],OUTPUT); //enable the mode pins -// pinMode(modePins[i][2],OUTPUT); //enable the mode pins -// digitalWrite(modePins[i][0],modeState[highSpeed[i]][0]); -// digitalWrite(modePins[i][1],modeState[highSpeed[i]][1]); -// digitalWrite(modePins[i][2],modeState[highSpeed[i]][2]); } #endif pinMode(resetPin[i],OUTPUT); //enable the reset pin @@ -548,7 +538,7 @@ void gotoMode(byte axis){ gotoRunning[axis] = 1; //start the goto. } -void timerEnable(byte motor, byte mode) { +inline void timerEnable(byte motor, byte mode) { //if (mode){ //FCPU/8 // timerPrescalarRegister(motor) &= ~((1<<CSn2) | (1<<CSn0)); //0x0 @@ -575,50 +565,111 @@ inline void timerDisable(byte motor) { timerPrescalarRegister(motor) &= ~((1<<CSn2) | (1<<CSn1) | (1<<CSn0));//00x } +//As there is plenty of FLASH left, then to improve speed, I have created two motorStart functions (one for RA and one for DEC) void motorStart(byte motor, unsigned int gotoDeceleration){ + if (motor == RA) { + motorStartRA(gotoDeceleration); + } else { + motorStartDC(gotoDeceleration); + } +} +void motorStartRA(unsigned int gotoDeceleration){ + unsigned int IVal = synta.cmd.IVal[RA]; + unsigned int currentIVal; + interruptControlRegister(RA) &= ~interruptControlBitMask(RA); //Disable timer interrupt + currentIVal = currentMotorSpeed(RA); + interruptControlRegister(RA) |= interruptControlBitMask(RA); //enable timer interrupt #ifdef DEBUG Serial1.println(F("IVal:")); - Serial1.println(synta.cmd.IVal[motor]); + Serial1.println(IVal); Serial1.println(); #endif - - unsigned int startSpeed = minSpeed[motor]; - if(synta.cmd.stopped[motor]) { - if (synta.cmd.IVal[motor] > startSpeed){ //With guiding running this may occur as minSpeed is just slower than sidereal speed. - startSpeed = synta.cmd.IVal[motor]; + unsigned int startSpeed; + unsigned int stoppingSpeed; + if (IVal > minSpeed[RA]){ + stoppingSpeed = IVal; + } else { + stoppingSpeed = minSpeed[RA]; + } + if(synta.cmd.stopped[RA]) { + startSpeed = stoppingSpeed; + } else { + if (currentIVal < minSpeed[RA]) { + startSpeed = currentIVal; + } else { + startSpeed = stoppingSpeed; } + } + + interruptControlRegister(RA) &= ~interruptControlBitMask(RA); //Disable timer interrupt + synta.cmd.currentIVal[RA] = synta.cmd.IVal[RA]; + currentMotorSpeed(RA) = startSpeed; + stopSpeed[RA] = stoppingSpeed; + interruptCount(RA) = 1; + if(synta.cmd.stopped[RA]) { //if stopped, configure timers + digitalWrite(dirPin[RA],encodeDirection[RA]^synta.cmd.dir[RA]); //set the direction + stepIncrementRepeat[RA] = 0; + distributionSegment(RA) = 0; + int* decelerationSteps = (int*)&decelerationStepsLow(RA); //low and high are in sequential registers so we can treat them as an int in the sram. + *decelerationSteps = -gotoDeceleration; + timerCountRegister(RA) = 0; + interruptOVFCount(RA) = timerOVF[RA][0]; + timerEnable(RA,highSpeed[RA]); + synta.cmd.setStopped(RA, 0); + } + interruptControlRegister(RA) |= interruptControlBitMask(RA); //enable timer interrupt +#ifdef DEBUG + Serial1.println(F("StartSpeed:")); + Serial1.println(startSpeed); + Serial1.println(); +#endif +} + +void motorStartDC(unsigned int gotoDeceleration){ + unsigned int IVal = synta.cmd.IVal[DC]; + unsigned int currentIVal; + interruptControlRegister(DC) &= ~interruptControlBitMask(DC); //Disable timer interrupt + currentIVal = currentMotorSpeed(DC); + interruptControlRegister(DC) |= interruptControlBitMask(DC); //enable timer interrupt +#ifdef DEBUG + Serial1.println(F("IVal:")); + Serial1.println(IVal); + Serial1.println(); +#endif + unsigned int startSpeed; + unsigned int stoppingSpeed; + if (IVal > minSpeed[DC]){ + stoppingSpeed = IVal; } else { - if ((synta.cmd.IVal[motor] > startSpeed) || (synta.cmd.currentIVal[motor] > startSpeed)){ //With guiding running this may occur as minSpeed is just slower than sidereal speed. - if (synta.cmd.IVal[motor] > synta.cmd.currentIVal[motor]){ - startSpeed = synta.cmd.IVal[motor]; - } else { - startSpeed = synta.cmd.currentIVal[motor]; - } + stoppingSpeed = minSpeed[DC]; + } + if(synta.cmd.stopped[DC]) { + startSpeed = stoppingSpeed; + } else { + if (currentIVal < minSpeed[DC]) { + startSpeed = currentIVal; + } else { + startSpeed = stoppingSpeed; } } - /*else if ((startSpeed > 650) && (synta.cmd.currentIVal[motor] <= 650)){ - startSpeed = 650; //if possible start closer to the target speed to avoid *very* long accelleration times. - }*/ - byte oldSREG = SREG; - cli(); - stopSpeed[motor] = startSpeed; - synta.cmd.currentIVal[motor] = synta.cmd.IVal[motor]; - SREG = oldSREG; - if(synta.cmd.stopped[motor]) { //if stopped, configure timers - digitalWrite(dirPin[motor],encodeDirection[motor]^synta.cmd.dir[motor]); //set the direction - stepIncrementRepeat[motor] = 0; - interruptCount(motor) = 1; - currentMotorSpeed(motor) = startSpeed;//minSpeed[motor]; - distributionSegment(motor) = 0; - int* decelerationSteps = (int*)&decelerationStepsLow(motor); //low and high are in sequential registers so we can treat them as an int in the sram. + interruptControlRegister(DC) &= ~interruptControlBitMask(DC); //Disable timer interrupt + synta.cmd.currentIVal[DC] = synta.cmd.IVal[DC]; + currentMotorSpeed(DC) = startSpeed; + stopSpeed[DC] = stoppingSpeed; + interruptCount(DC) = 1; + if(synta.cmd.stopped[DC]) { //if stopped, configure timers + digitalWrite(dirPin[DC],encodeDirection[DC]^synta.cmd.dir[DC]); //set the direction + stepIncrementRepeat[DC] = 0; + distributionSegment(DC) = 0; + int* decelerationSteps = (int*)&decelerationStepsLow(DC); //low and high are in sequential registers so we can treat them as an int in the sram. *decelerationSteps = -gotoDeceleration; - timerCountRegister(motor) = 0; - interruptControlRegister(motor) |= interruptControlBitMask(motor); - interruptOVFCount(motor) = timerOVF[motor][0]; - timerEnable(motor,highSpeed[motor]); - synta.cmd.setStopped(motor, 0); + timerCountRegister(DC) = 0; + interruptOVFCount(DC) = timerOVF[DC][0]; + timerEnable(DC,highSpeed[DC]); + synta.cmd.setStopped(DC, 0); } + interruptControlRegister(DC) |= interruptControlBitMask(DC); //enable timer interrupt #ifdef DEBUG Serial1.println(F("StartSpeed:")); Serial1.println(startSpeed); @@ -626,25 +677,64 @@ void motorStart(byte motor, unsigned int gotoDeceleration){ #endif } +//As there is plenty of FLASH left, then to improve speed, I have created two motorStop functions (one for RA and one for DEC) void motorStop(byte motor, byte emergency){ + if (motor == RA) { + motorStopRA(emergency); + } else { + motorStopDC(emergency); + } +} + +void motorStopRA(byte emergency){ + if (emergency) { + //trigger instant shutdown of the motor in an emergency. + timerDisable(RA); + synta.cmd.setGotoEn(RA,0); //Not in goto mode. + synta.cmd.setStopped(RA,1); //mark as stopped + readyToGo[RA] = 0; + gotoRunning[RA] = 0; + } else if (!synta.cmd.stopped[RA]){ //Only stop if not already stopped - for some reason EQMOD stops both axis when slewing, even if one isn't currently moving? + //trigger ISR based decelleration + //readyToGo[RA] = 0; + synta.cmd.setGotoEn(RA,0); //No longer in goto mode. + gotoRunning[RA] = 0; + interruptControlRegister(RA) &= ~interruptControlBitMask(RA); //Disable timer interrupt + if(synta.cmd.currentIVal[RA] < minSpeed[RA]){ + if(stopSpeed[RA] > minSpeed[RA]){ + stopSpeed[RA] = minSpeed[RA]; + } + }/* else { + stopSpeed[RA] = synta.cmd.currentIVal[RA]; + }*/ + synta.cmd.currentIVal[RA] = stopSpeed[RA] + 1;//synta.cmd.stepIncrement[motor]; + interruptControlRegister(RA) |= interruptControlBitMask(RA); //enable timer interrupt + } +} + +void motorStopDC(byte emergency){ if (emergency) { //trigger instant shutdown of the motor in an emergency. - timerDisable(motor); - synta.cmd.setGotoEn(motor,0); //Not in goto mode. - synta.cmd.setStopped(motor,1); //mark as stopped - readyToGo[motor] = 0; - gotoRunning[motor] = 0; - } else if (!synta.cmd.stopped[motor]){ //Only stop if not already stopped - for some reason EQMOD stops both axis when slewing, even if one isn't currently moving? + timerDisable(DC); + synta.cmd.setGotoEn(DC,0); //Not in goto mode. + synta.cmd.setStopped(DC,1); //mark as stopped + readyToGo[DC] = 0; + gotoRunning[DC] = 0; + } else if (!synta.cmd.stopped[DC]){ //Only stop if not already stopped - for some reason EQMOD stops both axis when slewing, even if one isn't currently moving? //trigger ISR based decelleration //readyToGo[motor] = 0; - synta.cmd.setGotoEn(motor,0); //No longer in goto mode. - gotoRunning[motor] = 0; - interruptControlRegister(motor) &= ~interruptControlBitMask(motor); //Disable timer interrupt - if(stopSpeed[motor] > minSpeed[motor]){ - stopSpeed[motor] = minSpeed[motor]; - } - synta.cmd.currentIVal[motor] = stopSpeed[motor] + 1;//synta.cmd.stepIncrement[motor]; - interruptControlRegister(motor) |= interruptControlBitMask(motor); //enable timer interrupt + synta.cmd.setGotoEn(DC,0); //No longer in goto mode. + gotoRunning[DC] = 0; + interruptControlRegister(DC) &= ~interruptControlBitMask(DC); //Disable timer interrupt + if(synta.cmd.currentIVal[DC] < minSpeed[DC]){ + if(stopSpeed[DC] > minSpeed[DC]){ + stopSpeed[DC] = minSpeed[DC]; + } + }/* else { + stopSpeed[DC] = synta.cmd.currentIVal[DC]; + }*/ + synta.cmd.currentIVal[DC] = stopSpeed[DC] + 1;//synta.cmd.stepIncrement[motor]; + interruptControlRegister(DC) |= interruptControlBitMask(DC); //enable timer interrupt } } diff --git a/AstroEQ-Firmware/HardwareSerial.cpp b/AstroEQ-Firmware/HardwareSerial.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2bde9208bb8ffa49ea369b884777130222f45a88 --- /dev/null +++ b/AstroEQ-Firmware/HardwareSerial.cpp @@ -0,0 +1,665 @@ +/* + HardwareSerial.cpp - Hardware serial library for Wiring + Copyright (c) 2006 Nicholas Zambetti. 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 + + Modified 23 November 2006 by David A. Mellis + Modified 28 September 2010 by Mark Sproul +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <inttypes.h> +#include "Arduino.h" +#include "wiring_private.h" + +// this next line disables the entire HardwareSerial.cpp, +// this is so I can support Attiny series and any other chip without a uart +#if defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(UBRR2H) || defined(UBRR3H) + +#include "HardwareSerial.h" + +// Define constants and variables for buffering incoming serial data. We're +// using a ring buffer (I think), in which head is the index of the location +// to which to write the next incoming character and tail is the index of the +// location from which to read. MAX SIZE IS 128 for this implementation!! +#if (RAMEND < 1000) + #define SERIAL_BUFFER_SIZE 16 +#else + #define SERIAL_BUFFER_SIZE 96 +#endif + +template<class T> inline T modulo(T head) { //Not a true '%' function, but it is all that is required by this library! + if(head >= SERIAL_BUFFER_SIZE){ + head -= SERIAL_BUFFER_SIZE; + } + return head; +} + +struct ring_buffer +{ + unsigned char buffer[SERIAL_BUFFER_SIZE]; + volatile unsigned char head; + volatile unsigned char tail; +}; + +#if defined(USBCON) + ring_buffer rx_buffer = { { 0 }, 0, 0}; + ring_buffer tx_buffer = { { 0 }, 0, 0}; +#endif +#if defined(UBRRH) || defined(UBRR0H) + ring_buffer rx_buffer = { { 0 }, 0, 0 }; + ring_buffer tx_buffer = { { 0 }, 0, 0 }; +#endif +#if defined(UBRR1H) + ring_buffer rx_buffer1 = { { 0 }, 0, 0 }; + ring_buffer tx_buffer1 = { { 0 }, 0, 0 }; +#endif +#if defined(UBRR2H) + ring_buffer rx_buffer2 = { { 0 }, 0, 0 }; + ring_buffer tx_buffer2 = { { 0 }, 0, 0 }; +#endif +#if defined(UBRR3H) + ring_buffer rx_buffer3 = { { 0 }, 0, 0 }; + ring_buffer tx_buffer3 = { { 0 }, 0, 0 }; +#endif + +inline void store_char(unsigned char c, ring_buffer *buffer) +{ + register unsigned char i asm("r25"); + register unsigned char tail asm("r24"); + asm volatile ( + "push %0 \n\t" + "push %1 \n\t" + "push r30 \n\t" + "push r31 \n\t" + ::"r" (i), "r" (tail): + ); + i = modulo((unsigned char)(buffer->head+1));// % SERIAL_BUFFER_SIZE; + // if we should be storing the received character into the location + // just before the tail (meaning that the head would advance to the + // current location of the tail), we're about to overflow the buffer + // and so we don't write the character or advance the head. + tail = buffer->tail; + if (i != tail) { + buffer->buffer[buffer->head] = c; + buffer->head = i; + } + asm volatile ( + "pop r31 \n\t" + "pop r30 \n\t" + "pop %1 \n\t" + "pop %0 \n\t" + :"=r" (i), "=r" (tail):: + ); +} + +#if !defined(USART0_RX_vect) && defined(USART1_RX_vect) +// do nothing - on the 32u4 the first USART is USART1 +#else +#if !defined(USART_RX_vect) && !defined(SIG_USART0_RECV) && \ + !defined(SIG_UART0_RECV) && !defined(USART0_RX_vect) && \ + !defined(SIG_UART_RECV) + #error "Don't know what the Data Received vector is called for the first UART" +#else + void serialEvent() __attribute__((weak)); + void serialEvent() {} + #define serialEvent_implemented +#if defined(USART_RX_vect) + ISR(USART_RX_vect,ISR_NAKED) +#elif defined(SIG_USART0_RECV) + ISR(SIG_USART0_RECV,ISR_NAKED) +#elif defined(SIG_UART0_RECV) + ISR(SIG_UART0_RECV,ISR_NAKED) +#elif defined(USART0_RX_vect) + ISR(USART0_RX_vect,ISR_NAKED) +#elif defined(SIG_UART_RECV) + ISR(SIG_UART_RECV,ISR_NAKED) +#endif + { + register unsigned char c asm("r18"); + asm volatile ( + "push %0 \n\t" + :: "a" (c): + ); + c = SREG; + asm volatile ( + "push %0 \n\t" + :: "a" (c): + ); + #if defined(UDR0) + c = UDR0; + #elif defined(UDR) + c = UDR; + #else + #error UDR not defined + #endif + store_char(c, &rx_buffer); + asm volatile ( + "pop %0 \n\t" + : "=a" (c):: + ); + SREG = c; + asm volatile ( + "pop %0 \n\t" + "reti \n\t" + : "=a" (c):: + ); + } +#endif +#endif + +#if defined(USART1_RX_vect) + void serialEvent1() __attribute__((weak)); + void serialEvent1() {} + #define serialEvent1_implemented + ISR(USART1_RX_vect,ISR_NAKED) + { + register unsigned char c asm("r18"); + asm volatile ( + "push %0 \n\t" + :: "a" (c): + ); + c = SREG; + asm volatile ( + "push %0 \n\t" + :: "a" (c): + ); + c = UDR1; + store_char(c, &rx_buffer1); + asm volatile ( + "pop %0 \n\t" + : "=a" (c):: + ); + SREG = c; + asm volatile ( + "pop %0 \n\t" + "reti \n\t" + : "=a" (c):: + ); + } +#elif defined(SIG_USART1_RECV) + #error SIG_USART1_RECV +#endif + +#if defined(USART2_RX_vect) && defined(UDR2) + void serialEvent2() __attribute__((weak)); + void serialEvent2() {} + #define serialEvent2_implemented + ISR(USART2_RX_vect,ISR_NAKED) + { + register unsigned char c asm("r18"); + asm volatile ( + "push %0 \n\t" + :: "a" (c): + ); + c = SREG; + asm volatile ( + "push %0 \n\t" + :: "a" (c): + ); + c = UDR2; + store_char(c, &rx_buffer2); + asm volatile ( + "pop %0 \n\t" + : "=a" (c):: + ); + SREG = c; + asm volatile ( + "pop %0 \n\t" + "reti \n\t" + : "=a" (c):: + ); + } +#elif defined(SIG_USART2_RECV) + #error SIG_USART2_RECV +#endif + +#if defined(USART3_RX_vect) && defined(UDR3) + void serialEvent3() __attribute__((weak)); + void serialEvent3() {} + #define serialEvent3_implemented + ISR(USART3_RX_vect,ISR_NAKED) + { + register unsigned char c asm("r18"); + asm volatile ( + "push %0 \n\t" + :: "a" (c): + ); + c = SREG; + asm volatile ( + "push %0 \n\t" + :: "a" (c): + ); + c = UDR3; + store_char(c, &rx_buffer3); + asm volatile ( + "pop %0 \n\t" + : "=a" (c):: + ); + SREG = c; + asm volatile ( + "pop %0 \n\t" + "reti \n\t" + : "=a" (c):: + ); + } +#elif defined(SIG_USART3_RECV) + #error SIG_USART3_RECV +#endif + +void serialEventRun(void) +{ +#ifdef serialEvent_implemented + if (Serial.available()) serialEvent(); +#endif +#ifdef serialEvent1_implemented + if (Serial1.available()) serialEvent1(); +#endif +#ifdef serialEvent2_implemented + if (Serial2.available()) serialEvent2(); +#endif +#ifdef serialEvent3_implemented + if (Serial3.available()) serialEvent3(); +#endif +} + + +#if !defined(USART0_UDRE_vect) && defined(USART1_UDRE_vect) +// do nothing - on the 32u4 the first USART is USART1 +#else +#if !defined(UART0_UDRE_vect) && !defined(UART_UDRE_vect) && !defined(USART0_UDRE_vect) && !defined(USART_UDRE_vect) + #error "Don't know what the Data Register Empty vector is called for the first UART" +#else +#if defined(UART0_UDRE_vect) +ISR(UART0_UDRE_vect, ISR_NAKED) +#elif defined(UART_UDRE_vect) +ISR(UART_UDRE_vect, ISR_NAKED) +#elif defined(USART0_UDRE_vect) +ISR(USART0_UDRE_vect, ISR_NAKED) +#elif defined(USART_UDRE_vect) +ISR(USART_UDRE_vect, ISR_NAKED) +#endif +{ + register unsigned char tail asm("r25"); + register unsigned char head asm("r24"); + register unsigned char ch asm("r18"); + asm volatile ( + "push %0 \n\t" + :: "r" (tail): + ); + tail = SREG; + asm volatile ( + "push %0 \n\t" + "push %1 \n\t" + "push %2 \n\t" + "push r30 \n\t" + "push r31 \n\t" + :: "r" (tail), "r" (head), "r" (ch): + ); + tail = tx_buffer.tail; + head = tx_buffer.head; + if (head == tail) { + // Buffer empty, so disable interrupts +#if defined(UCSR0B) + cbi(UCSR0B, UDRIE0); +#else + cbi(UCSRB, UDRIE); +#endif + } + else { + // There is more data in the output buffer. Send the next byte + ch = tx_buffer.buffer[tail]; + tx_buffer.tail = modulo(++tail); + //tx_buffer.tail = (tx_buffer.tail + 1) % SERIAL_BUFFER_SIZE; + + #if defined(UDR0) + UDR0 = ch; + #elif defined(UDR) + UDR = ch; + #else + #error UDR not defined + #endif + } + asm volatile ( + "pop r31 \n\t" + "pop r30 \n\t" + "pop %2 \n\t" + "pop %1 \n\t" + "pop %0 \n\t" + :"=r" (tail), "=r" (head), "=r" (ch):: + ); + SREG = tail; + asm volatile ( + "pop %0 \n\t" + "reti \n\t" + :"=r" (tail):: + ); +} +#endif +#endif + +#ifdef USART1_UDRE_vect +ISR(USART1_UDRE_vect, ISR_NAKED) +{ + register unsigned char tail asm("r25"); + register unsigned char head asm("r24"); + register unsigned char ch asm("r18"); + asm volatile ( + "push %0 \n\t" + :: "r" (tail): + ); + tail = SREG; + asm volatile ( + "push %0 \n\t" + "push %1 \n\t" + "push %2 \n\t" + "push r30 \n\t" + "push r31 \n\t" + :: "r" (tail), "r" (head), "r" (ch): + ); + tail = tx_buffer1.tail; + head = tx_buffer1.head; + if (head == tail) { + // Buffer empty, so disable interrupts + cbi(UCSR1B, UDRIE1); + } + else { + // There is more data in the output buffer. Send the next byte + head = tx_buffer1.buffer[tail]; + tx_buffer1.tail = modulo(++tail); + //tx_buffer1.tail = (tx_buffer1.tail + 1) % SERIAL_BUFFER_SIZE; + + UDR1 = head; + } + asm volatile ( + "pop r31 \n\t" + "pop r30 \n\t" + "pop %2 \n\t" + "pop %1 \n\t" + "pop %0 \n\t" + :"=r" (tail), "=r" (head), "=r" (ch):: + ); + SREG = tail; + asm volatile ( + "pop %0 \n\t" + "reti \n\t" + :"=r" (tail):: + ); +} +#endif + +#ifdef USART2_UDRE_vect +ISR(USART2_UDRE_vect, ISR_NAKED) +{ + register unsigned char tail asm("r25"); + register unsigned char head asm("r24"); + register unsigned char ch asm("r18"); + asm volatile ( + "push %0 \n\t" + :: "r" (tail): + ); + tail = SREG; + asm volatile ( + "push %0 \n\t" + "push %1 \n\t" + "push %2 \n\t" + "push r30 \n\t" + "push r31 \n\t" + :: "r" (tail), "r" (head), "r" (ch): + ); + tail = tx_buffer2.tail; + head = tx_buffer2.head; + if (head == tail) { + // Buffer empty, so disable interrupts + cbi(UCSR2B, UDRIE2); + } + else { + // There is more data in the output buffer. Send the next byte + head = tx_buffer2.buffer[tail]; + tx_buffer2.tail = modulo(++tail); + //tx_buffer2.tail = (tx_buffer2.tail + 1) % SERIAL_BUFFER_SIZE; + + UDR2 = head; + } + asm volatile ( + "pop r31 \n\t" + "pop r30 \n\t" + "pop %2 \n\t" + "pop %1 \n\t" + "pop %0 \n\t" + :"=r" (tail), "=r" (head), "=r" (ch):: + ); + SREG = tail; + asm volatile ( + "pop %0 \n\t" + "reti \n\t" + :"=r" (tail):: + ); +} +#endif + +#ifdef USART3_UDRE_vect +ISR(USART3_UDRE_vect, ISR_NAKED) +{ + register unsigned char tail asm("r25"); + register unsigned char head asm("r24"); + register unsigned char ch asm("r18"); + asm volatile ( + "push %0 \n\t" + :: "r" (tail): + ); + tail = SREG; + asm volatile ( + "push %0 \n\t" + "push %1 \n\t" + "push %2 \n\t" + "push r30 \n\t" + "push r31 \n\t" + :: "r" (tail), "r" (head), "r" (ch): + ); + tail = tx_buffer3.tail; + head = tx_buffer3.head; + if (head == tail) { + // Buffer empty, so disable interrupts + cbi(UCSR3B, UDRIE3); + } + else { + // There is more data in the output buffer. Send the next byte + head = tx_buffer3.buffer[tail]; + tx_buffer3.tail = modulo(++tail); + //tx_buffer3.tail = (tx_buffer3.tail + 1) % SERIAL_BUFFER_SIZE; + + UDR3 = head; + } + asm volatile ( + "pop r31 \n\t" + "pop r30 \n\t" + "pop %2 \n\t" + "pop %1 \n\t" + "pop %0 \n\t" + :"=r" (tail), "=r" (head), "=r" (ch):: + ); + SREG = tail; + asm volatile ( + "pop %0 \n\t" + "reti \n\t" + :"=r" (tail):: + ); +} +#endif + + +// Constructors //////////////////////////////////////////////////////////////// + +HardwareSerial::HardwareSerial(ring_buffer *rx_buffer, ring_buffer *tx_buffer, + volatile uint8_t *ubrrh, volatile uint8_t *ubrrl, + volatile uint8_t *ucsra, volatile uint8_t *ucsrb, + volatile uint8_t *udr, + uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udrie, uint8_t u2x) +{ + _rx_buffer = rx_buffer; + _tx_buffer = tx_buffer; + _ubrrh = ubrrh; + _ubrrl = ubrrl; + _ucsra = ucsra; + _ucsrb = ucsrb; + _udr = udr; + _rxen = rxen; + _txen = txen; + _rxcie = rxcie; + _udrie = udrie; + _u2x = u2x; +} + +// Public Methods ////////////////////////////////////////////////////////////// + +void HardwareSerial::begin(unsigned long baud) +{ + uint16_t baud_setting; + bool use_u2x = true; + +#if (F_CPU == 16000000UL) || (F_CPU == 24000000UL) + // hardcoded exception for compatibility with the bootloader shipped + // with the Duemilanove and previous boards and the firmware on the 8U2 + // on the Uno and Mega 2560. + if (baud == 57600) { + use_u2x = false; + } +#endif + +try_again: + + if (use_u2x) { + *_ucsra = 1 << _u2x; + baud_setting = (F_CPU / 4 / baud - 1) / 2; + } else { + *_ucsra = 0; + baud_setting = (F_CPU / 8 / baud - 1) / 2; + } + + if ((baud_setting > 4095) && use_u2x) + { + use_u2x = false; + goto try_again; + } + + // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register) + *_ubrrh = baud_setting >> 8; + *_ubrrl = baud_setting; + + sbi(*_ucsrb, _rxen); + sbi(*_ucsrb, _txen); + sbi(*_ucsrb, _rxcie); + cbi(*_ucsrb, _udrie); +} + +void HardwareSerial::end() +{ + // wait for transmission of outgoing data + while (_tx_buffer->head != _tx_buffer->tail) + ; + + cbi(*_ucsrb, _rxen); + cbi(*_ucsrb, _txen); + cbi(*_ucsrb, _rxcie); + cbi(*_ucsrb, _udrie); + + // clear any received data + _rx_buffer->head = _rx_buffer->tail; +} + +int HardwareSerial::available(void) +{ + unsigned int difference = SERIAL_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail; + return modulo(difference); + //return (unsigned int)(SERIAL_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % SERIAL_BUFFER_SIZE; +} + +int HardwareSerial::peek(void) +{ + if (_rx_buffer->head == _rx_buffer->tail) { + return -1; + } else { + return _rx_buffer->buffer[_rx_buffer->tail]; + } +} + +int HardwareSerial::read(void) +{ + // if the head isn't ahead of the tail, we don't have any characters + if (_rx_buffer->head == _rx_buffer->tail) { + return -1; + } else { + unsigned char c = _rx_buffer->buffer[_rx_buffer->tail]; + _rx_buffer->tail = modulo(++_rx_buffer->tail);//(unsigned int)(_rx_buffer->tail + 1) % SERIAL_BUFFER_SIZE; + return c; + } +} + +void HardwareSerial::flush() +{ + while (_tx_buffer->head != _tx_buffer->tail) + ; +} + +size_t HardwareSerial::write(uint8_t c) +{ + unsigned char i = modulo((unsigned char)(_tx_buffer->head+1));//(unsigned char)((_tx_buffer->head + 1) % SERIAL_BUFFER_SIZE); + + // If the output buffer is full, there's nothing for it other than to + // wait for the interrupt handler to empty it a bit + // ???: return 0 here instead? + while (i == _tx_buffer->tail) + ; + + _tx_buffer->buffer[_tx_buffer->head] = c; + _tx_buffer->head = i; + + sbi(*_ucsrb, _udrie); + + return 1; +} + +HardwareSerial::operator bool() { + return true; +} + +// Preinstantiate Objects ////////////////////////////////////////////////////// + +#if defined(UBRRH) && defined(UBRRL) + HardwareSerial Serial(&rx_buffer, &tx_buffer, &UBRRH, &UBRRL, &UCSRA, &UCSRB, &UDR, RXEN, TXEN, RXCIE, UDRIE, U2X); +#elif defined(UBRR0H) && defined(UBRR0L) + HardwareSerial Serial(&rx_buffer, &tx_buffer, &UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UDR0, RXEN0, TXEN0, RXCIE0, UDRIE0, U2X0); +#elif defined(USBCON) + // do nothing - Serial object and buffers are initialized in CDC code +#else + #error no serial port defined (port 0) +#endif + +#if defined(UBRR1H) + HardwareSerial Serial1(&rx_buffer1, &tx_buffer1, &UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UDR1, RXEN1, TXEN1, RXCIE1, UDRIE1, U2X1); +#endif +#if defined(UBRR2H) + HardwareSerial Serial2(&rx_buffer2, &tx_buffer2, &UBRR2H, &UBRR2L, &UCSR2A, &UCSR2B, &UDR2, RXEN2, TXEN2, RXCIE2, UDRIE2, U2X2); +#endif +#if defined(UBRR3H) + HardwareSerial Serial3(&rx_buffer3, &tx_buffer3, &UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UDR3, RXEN3, TXEN3, RXCIE3, UDRIE3, U2X3); +#endif + +#endif // whole file + diff --git a/AstroEQ-Firmware/HardwareSerial.h b/AstroEQ-Firmware/HardwareSerial.h new file mode 100644 index 0000000000000000000000000000000000000000..bf4924c6d4abf4b54f5197592f5dfcc9cfd721c6 --- /dev/null +++ b/AstroEQ-Firmware/HardwareSerial.h @@ -0,0 +1,81 @@ +/* + HardwareSerial.h - Hardware serial library for Wiring + Copyright (c) 2006 Nicholas Zambetti. 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 + + Modified 28 September 2010 by Mark Sproul +*/ + +#ifndef HardwareSerial_h +#define HardwareSerial_h + +#include <inttypes.h> + +#include "Stream.h" + +struct ring_buffer; + +class HardwareSerial : public Stream +{ + private: + ring_buffer *_rx_buffer; + ring_buffer *_tx_buffer; + volatile uint8_t *_ubrrh; + volatile uint8_t *_ubrrl; + volatile uint8_t *_ucsra; + volatile uint8_t *_ucsrb; + volatile uint8_t *_udr; + uint8_t _rxen; + uint8_t _txen; + uint8_t _rxcie; + uint8_t _udrie; + uint8_t _u2x; + public: + HardwareSerial(ring_buffer *rx_buffer, ring_buffer *tx_buffer, + volatile uint8_t *ubrrh, volatile uint8_t *ubrrl, + volatile uint8_t *ucsra, volatile uint8_t *ucsrb, + volatile uint8_t *udr, + uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udrie, uint8_t u2x); + void begin(unsigned long); + void end(); + virtual int available(void); + virtual int peek(void); + virtual int read(void); + virtual void flush(void); + virtual size_t write(uint8_t); + using Print::write; // pull in write(str) and write(buf, size) from Print + operator bool(); +}; + +#if defined(UBRRH) || defined(UBRR0H) + extern HardwareSerial Serial; +#elif defined(USBCON) + #include "USBAPI.h" +// extern HardwareSerial Serial_; +#endif +#if defined(UBRR1H) + extern HardwareSerial Serial1; +#endif +#if defined(UBRR2H) + extern HardwareSerial Serial2; +#endif +#if defined(UBRR3H) + extern HardwareSerial Serial3; +#endif + +extern void serialEventRun(void) __attribute__((weak)); + +#endif diff --git a/AstroEQ-Firmware/README.txt b/AstroEQ-Firmware/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..27a871b022f4a326a6527b2a8a3ee2ce81420336 --- /dev/null +++ b/AstroEQ-Firmware/README.txt @@ -0,0 +1,8 @@ +Replace the following two files: + +HardwareSerial.h +HardwareSerial.cpp + +In the directory: + +<arduino install>\hardware\arduino\cores\arduino \ No newline at end of file diff --git a/AstroEQ-Firmware/synta.cpp b/AstroEQ-Firmware/synta.cpp index c7cec63807e64531d94f41ca9ef75c06b4eb857f..00a8f11363e686a7ca8c023975e4879a68d6af70 100644 --- a/AstroEQ-Firmware/synta.cpp +++ b/AstroEQ-Firmware/synta.cpp @@ -9,7 +9,7 @@ void Synta::initialise(unsigned long eVal){ clearBuffer(commandString,sizeof(commandString)); //scalar[0] = EEPROM.readByte(scalar1_Address) - 1; //scalar[1] = EEPROM.readByte(scalar2_Address) - 1; - cmd.init(eVal, 8); + cmd.init(eVal, 1); } const char Synta::startInChar = ':'; diff --git a/Downloads/AstroEQ6-ConfigUtility.zip b/Downloads/AstroEQ6-ConfigUtility.zip index 47be68ba69a3c813f8660702a1c95a906bffb6c5..eb3b2d8015c249a9070c5de83baec0166a9abdd9 100644 Binary files a/Downloads/AstroEQ6-ConfigUtility.zip and b/Downloads/AstroEQ6-ConfigUtility.zip differ diff --git a/Downloads/AstroEQ6-Firmware.zip b/Downloads/AstroEQ6-Firmware.zip index e462e011368a2be9cfd6dc00d4b3dc89125bf0a2..2aa1d9281e62b1b49ec1ffc10f3f1fae9a355ecd 100644 Binary files a/Downloads/AstroEQ6-Firmware.zip and b/Downloads/AstroEQ6-Firmware.zip differ diff --git a/README b/README index cb7a613ef18fbb5f7161a4fa28af6e18769fd0eb..ff9df85f9d487966df2495744867cdafe3893ea8 100644 --- a/README +++ b/README @@ -1,6 +1,4 @@ -Last Updated: 10/11/2013 - -To use version 6.5 you will need to download the lastest config utility. There were changes made to the utility which are required for compatibility with firmware version 6.5. +Last Updated: 31/12/2013 A small number of AstroEQ controllers are available to purchase. These can be bought from me on the AstronomyShed forum. Just send me a PM on Astronomy Shed (http://www.astronomyshed.co.uk/forum/memberlist.php?mode=viewprofile&u=2603). @@ -25,7 +23,7 @@ The EQMOD Project can be found at: http://eq-mod.sourceforge.net/ Works with EQ3, EQ5, HEQ5, and EQ6 mounts. Along With custom mounts. - Current Software Verison: 6.5 + Current Software Verison: 6.7 Current Hardware Version: 4.1 ---------------------------------------------------------------------------------------