summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--firmware/main.c64
-rw-r--r--firmware/osccalASM.S70
-rw-r--r--firmware/usbconfig.h2
-rw-r--r--firmware/usbdrv/asmcommon.inc2
-rw-r--r--firmware/usbdrv/usbdrvasm165.inc23
5 files changed, 105 insertions, 56 deletions
diff --git a/firmware/main.c b/firmware/main.c
index 1fdda03..a09bb4c 100644
--- a/firmware/main.c
+++ b/firmware/main.c
@@ -125,19 +125,21 @@ static void writeWordToPageBuffer(uint16_t data) {
vectorTemp[0] = data;
data = 0xC000 + (BOOTLOADER_ADDRESS/2) - 1;
}
-
+/*
if (currentAddress.w == USBPLUS_VECTOR_OFFSET * 2) {
vectorTemp[1] = data;
data = 0xC000 + (BOOTLOADER_ADDRESS/2) - 1;
}
-
+ */
// at end of page just before bootloader, write in tinyVector table
// see http://embedded-creations.com/projects/attiny85-usb-bootloader-overview/avr-jtag-programmer/
// for info on how the tiny vector table works
if (currentAddress.w == BOOTLOADER_ADDRESS - TINYVECTOR_RESET_OFFSET) {
data = vectorTemp[0] + ((FLASHEND + 1) - BOOTLOADER_ADDRESS)/2 + 2 + RESET_VECTOR_OFFSET;
+/*
} else if (currentAddress.w == BOOTLOADER_ADDRESS - TINYVECTOR_USBPLUS_OFFSET) {
data = vectorTemp[1] + ((FLASHEND + 1) - BOOTLOADER_ADDRESS)/2 + 1 + USBPLUS_VECTOR_OFFSET;
+*/
#if (!OSCCAL_RESTORE) && OSCCAL_16_5MHz
} else if (currentAddress.w == BOOTLOADER_ADDRESS - TINYVECTOR_OSCCAL_OFFSET) {
data = OSCCAL;
@@ -286,7 +288,7 @@ static void wait_usb_interrupt( void )
USB_INTR_VECTOR();
// Wait a little while longer in case another one comes
- uchar n = 250; // about 90us timeout
+ uchar n = 50; // about 90us timeout
do {
if ( !--n )
goto handled;
@@ -302,6 +304,8 @@ int main(void) {
bootLoaderInit();
+ DDRB|=3;
+
if (bootLoaderStartCondition()||(pgm_read_byte(BOOTLOADER_ADDRESS - TINYVECTOR_RESET_OFFSET + 1)==0xff)) {
initHardware();
@@ -314,7 +318,9 @@ int main(void) {
}
do {
-
+// USB_INTR_PENDING = 1<<USB_INTR_PENDING_BIT; // <--
+
+/*
uint8_t n=200;
while (--n)
{
@@ -323,12 +329,58 @@ int main(void) {
// Vector interrupt manually
USB_INTR_PENDING = 1<<USB_INTR_PENDING_BIT;
USB_INTR_VECTOR();
- n=100;
+ n=50; // 25µs
}
}
+ */
+
+
+ while ( !(USB_INTR_PENDING & (1<<USB_INTR_PENDING_BIT)) );
+ USB_INTR_VECTOR();
+
+
command=cmd_local_nop;
+ PORTB|=_BV(PB1);
+ USB_INTR_PENDING = 1<<USB_INTR_PENDING_BIT;
usbPoll();
-
+
+ // Test whether another interrupt occured during the processing of USBpoll.
+ // If yes, we missed a data packet on the bus. This is not a big issue, since
+ // USB seems to allow timeout of up the two packets. (On my machine an USB
+ // error is triggers after the third missed packet.)
+ // The most critical situation occurs when a PID IN packet is missed due to
+ // it's short length. Each packet + timeout takes around 45µs, meaning that
+ // usbpoll must take less than 90µs or resyncing is not possible.
+ // To avoid synchronizing of the interrupt routine, we must not call it while
+ // a packet is transmitted. Therefore we have to wait until the bus is idle again.
+ //
+ // Just waiting for EOP (SE0) or no activity for 6 bus cycles is not enough,
+ // as the host may have been sending a multi-packet transmisstion (eg. OUT, DATA0/1)
+ // Restarting at the DATA packet may lead to errors.
+ //
+ // A safer way is to wait until the bus was idle for the the host-timeout
+ // period (18 bit times = 12µs).
+
+ if (USB_INTR_PENDING & (1<<USB_INTR_PENDING_BIT)) // Usbpoll intersected with data packe
+ {
+ PORTB|=_BV(PB0);
+ uint8_t tx;
+ uint8_t timeout=(uint8_t)(10.0f*(F_CPU/1.0e6f)/7.0f+0.5);
+ tx=timeout;
+
+ // loop takes 9 cycles
+ while (--tx) {
+ uint8_t usbin=USBIN;
+
+ if (usbin&(1<<USB_CFG_DPLUS_BIT)) {tx=timeout;}
+ // if (!(usbin&USBMASK)) {t=2;}
+
+ }
+ USB_INTR_PENDING = 1<<USB_INTR_PENDING_BIT;
+ PORTB&=~_BV(PB0);
+ }
+ PORTB&=~_BV(PB1);
+
if ( command != cmd_local_nop)
{
// Make sure all USB activity has finished before running any blocking events
diff --git a/firmware/osccalASM.S b/firmware/osccalASM.S
index c0c8803..9c3b45a 100644
--- a/firmware/osccalASM.S
+++ b/firmware/osccalASM.S
@@ -1,6 +1,8 @@
-/* Name: osccalASM.S
+/* Name: osccalASM.S v1.1
* Author: cpldcpu@gmail.com
* Creation Date: 2013-11-3
+ * Update : 2014-01-4
+ *
* Tabsize: 4
* License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
*/
@@ -11,28 +13,34 @@
*
*
* Benefits:
- * - Codesize reduced by 90 bytes.
+ * - Codesize reduced by 90 bytes.
* - Improved robustness due to removing timeout from frame length measurement and
- * inserted NOP after OSCCAL writes.
+ * inserted NOP after OSCCAL writes.
*
* Changes:
* - The new routine performs a combined binary and neighborhood search
* in a single loop.
* Note that the neighborhood search is necessary due to the quasi-monotonic
* nature of OSCCAL. (See Atmel application note AVR054).
- * - Inserted NOP after writes to OSCCAL to avoid CPU errors during oscillator
+ * - Inserted NOP after writes to OSCCAL to avoid CPU errors during oscillator
* stabilization.
* - Implemented new routine to measure frame time "usbMeasureFrameLengthDecreasing".
- * This routine takes the target time as a parameter and returns the deviation.
- * - usbMeasureFrameLengthDecreasing measures in multiples of 5 cycles and is thus
- * slighly more accurate.
- * - usbMeasureFrameLengthDecreasing does not support time out anymore. The original
- * implementation returned zero in case of time out, which would have caused the old
+ * This routine takes the target time as a parameter and returns the deviation.
+ * - usbMeasureFrameLengthDecreasing measures in multiples of 5 cycles and is thus
+ * slighly more accurate.
+ * - usbMeasureFrameLengthDecreasing does not support time out anymore. The original
+ * implementation returned zero in case of time out, which would have caused the old
* calibrateOscillator() implementation to increase OSSCAL to 255, effictively
* overclocking and most likely crashing the CPU. The new implementation will enter
- * an infinite loop when no USB activity is encountered. The user program should
+ * an infinite loop when no USB activity is encountered. The user program should
* use the watchdog to escape from situations like this.
- *
+ * Update 2014-01-4
+ * - Added an initial sync-state, which will discard the first delay measurement.
+ * This allows to call this routine before or during the SE0 bus reset without
+ * corrupting OSCCAL.
+ * - Removed CLI/SEI to allow more flexibility.
+ *
+ *
* This routine will work both on controllers with and without split OSCCAL range.
* The first trial value is 128 which is the lowest value of the upper OSCCAL range
* on Attiny85 and will effectively limit the search to the upper range, unless the
@@ -90,20 +98,19 @@
.global calibrateOscillatorASM
calibrateOscillatorASM:
-; cli
- ldi opD, 255
+ ldi opD, 255
- ldi try, 128 ; calibration start value
- ldi stp, 64 ; initial step width
- ldi i, 10 ; 10 iterations
+ ldi try, 128 ; calibration start value
+ ldi stp, 0 ; initial step width=0 for sync phase (first delay is discarded)
+ ldi i, 11 ; 11 iterations (1x sync, 7x binary search, 3x neighbourhood)
usbCOloop:
- out OSCCAL, try
- nop
+ out OSCCAL, try
+ nop
- ; Delay values = F_CPU * 999e-6 / 5 + 0.5
-
+ ; Delay values = F_CPU * 999e-6 / 5 + 0.5
+
#if (F_CPU == 16500000)
ldi cnt16L, lo8(3297)
ldi cnt16H, hi8(3297)
@@ -115,9 +122,9 @@ usbCOloop:
ldi cnt16H, hi8(2398)
#elif (F_CPU == 16000000)
ldi cnt16L, lo8(3197)
- ldi cnt16H, hi8(3197)
+ ldi cnt16H, hi8(3197)
#else
- #error "calibrateOscillatorASM: no delayvalues defined for this F_CPU setting"
+ #error "calibrateOscillatorASM: no delayvalues defined for this F_CPU setting"
#endif
usbCOWaitStrobe: ; first wait for D- == 0 (idle strobe)
@@ -139,21 +146,26 @@ usbCOWaitLoop:
usbCOclocktoolow:
add try, stp
usbCOclocktoohigh:
- lsr stp
- brne usbCOnoneighborhoodsearch
+ lsr stp ; stp = 0 in first iteration (sync)
+ ; stp = 2^x (x=0..6) during binary search,
+ ; stp = 1 during neighbourhood search
+
+ brne usbCObinarysearch
+ ldi stp, 64 ; stp=64 to initiate binary search.
+ ; If we are in neighbourhood search (c=1), it is changed to 1 below
+ brcc usbCObinarysearch
cp opD, cnt16L
brcs usbCOnoimprovement
in opV, OSCCAL
mov opD, cnt16L
usbCOnoimprovement:
- ldi stp, 1
-usbCOnoneighborhoodsearch:
+ ldi stp, 1 ; stp=1 to continue with neighbourhood search
+usbCObinarysearch:
subi i, 1
brne usbCOloop
out OSCCAL, opV
nop
-; sei
ret
#undef i
@@ -227,8 +239,6 @@ void calibrateOscillator(void)
}
OSCCAL = optimumValue;
- asm volatile(" NOP");
-
- sei(); // enable interrupts
+ asm volatile(" NOP");
}
#endif \ No newline at end of file
diff --git a/firmware/usbconfig.h b/firmware/usbconfig.h
index 6de0611..3dda6b2 100644
--- a/firmware/usbconfig.h
+++ b/firmware/usbconfig.h
@@ -112,10 +112,12 @@
/* #define USB_RX_USER_HOOK(data, len) if(usbRxToken == (uchar)USBPID_SETUP) blinkLED(); */
// Check CRC of all received data
+/*
#define USB_RX_USER_HOOK( data, len ) { \
if ( usbCrc16( data, len + 2 ) != 0x4FFE )\
return;\
}
+*/
/* This macro is a hook if you want to do unconventional things. If it is
* defined, it's inserted at the beginning of received message processing.
* If you eat the received message and don't want default processing to
diff --git a/firmware/usbdrv/asmcommon.inc b/firmware/usbdrv/asmcommon.inc
index 5e525f5..b7efadb 100644
--- a/firmware/usbdrv/asmcommon.inc
+++ b/firmware/usbdrv/asmcommon.inc
@@ -99,6 +99,8 @@ doReturn:
rjmp waitForJ ;[51] save the pops and pushes -- a new interrupt is already pending
sofError:
POP_RETI ;macro call
+
+ CBI PORTB,0
; reti
ret
diff --git a/firmware/usbdrv/usbdrvasm165.inc b/firmware/usbdrv/usbdrvasm165.inc
index 20457f4..a6c76f6 100644
--- a/firmware/usbdrv/usbdrvasm165.inc
+++ b/firmware/usbdrv/usbdrvasm165.inc
@@ -45,30 +45,13 @@ of CPU cycles, but even an exact number of cycles!
USB_INTR_VECTOR:
;order of registers pushed: YL, SREG [sofError], r0, YH, shift, x1, x2, x3, x4, cnt
+ SBI PORTB,0
+
push YL ; push only what is necessary to sync with edge ASAP
in YL, SREG ;
push YL ;
-#if 0
- cpi YL, 0xB0
- brne cleanupAndJumpToApp
-
- lds YL, RAMEND-1
- cpi YL, 0x07
- breq cleanupBootloaderIntStack
-
-cleanupAndJumpToApp:
-; magic word was not found, put registers back to where they were before this ISR ran, and jump to application ISR
- pop YL
- out SREG, YL
- pop YL
-
- rjmp __vectors - TINYVECTOR_USBPLUS_OFFSET
-
-cleanupBootloaderIntStack:
-; magic word was found, put registers
- CLR YL ; [-19] ensure we meet below requirements for YL < 0x80
-#endif
+
;----------------------------------------------------------------------------
; Synchronize with sync pattern:
;----------------------------------------------------------------------------