summaryrefslogtreecommitdiffstats
path: root/firmware/usbdrv
diff options
context:
space:
mode:
authorcpldcpu <cpldcpu@gmail.com>2013-11-04 05:11:22 +0100
committercpldcpu <cpldcpu@gmail.com>2013-11-04 05:11:22 +0100
commitd7360925c1170acbc3a7b98c50e48350ac80fbc7 (patch)
tree6c4be92ab12aab00d17e264ef1796f05dec574f3 /firmware/usbdrv
parent819ce8ac705e9a336cb60fdb6f525a17cbc9dcb3 (diff)
downloadmicronucleus-d7360925c1170acbc3a7b98c50e48350ac80fbc7.tar.gz
micronucleus-d7360925c1170acbc3a7b98c50e48350ac80fbc7.tar.bz2
micronucleus-d7360925c1170acbc3a7b98c50e48350ac80fbc7.zip
assembler version of calibrateoscillator - 1952 bytes
still needs cleaning up
Diffstat (limited to 'firmware/usbdrv')
-rw-r--r--firmware/usbdrv/usbdrvasm.S200
1 files changed, 199 insertions, 1 deletions
diff --git a/firmware/usbdrv/usbdrvasm.S b/firmware/usbdrv/usbdrvasm.S
index b03b709..29c634a 100644
--- a/firmware/usbdrv/usbdrvasm.S
+++ b/firmware/usbdrv/usbdrvasm.S
@@ -282,7 +282,81 @@ usbCrc16Append:
#undef scratch
-#if USB_CFG_HAVE_MEASURE_FRAME_LENGTH
+#if USB_CFG_HAVE_MEASURE_FRAME_LENGTHx
+#ifdef __IAR_SYSTEMS_ASM__
+/* Register assignments for usbMeasureFrameLength on IAR cc */
+/* Calling conventions on IAR:
+ * First parameter passed in r16/r17, second in r18/r19 and so on.
+ * Callee must preserve r4-r15, r24-r29 (r28/r29 is frame pointer)
+ * Result is passed in r16/r17
+ * In case of the "tiny" memory model, pointers are only 8 bit with no
+ * padding. We therefore pass argument 1 as "16 bit unsigned".
+ */
+# define resL r16
+# define resH r17
+# define cnt16L r30
+# define cnt16H r31
+# define cntH r18
+
+#else /* __IAR_SYSTEMS_ASM__ */
+/* Register assignments for usbMeasureFrameLength on gcc */
+/* Calling conventions on gcc:
+ * First parameter passed in r24/r25, second in r22/23 and so on.
+ * Callee must preserve r1-r17, r28/r29
+ * Result is passed in r24/r25
+ */
+# define resL r24
+# define resH r25
+# define cnt16L r24
+# define cnt16H r25
+# define cntH r26
+#endif
+# define cnt16 cnt16L
+
+; extern unsigned usbMeasurePacketLength(void);
+; returns time between two idle strobes in multiples of 7 CPU clocks
+.global usbMeasureFrameLength
+usbMeasureFrameLength:
+ ldi cntH, 6 ; wait ~ 10 ms for D- == 0
+ clr cnt16L
+ clr cnt16H
+usbMFTime16:
+ dec cntH
+ breq usbMFTimeout
+usbMFWaitStrobe: ; first wait for D- == 0 (idle strobe)
+ sbiw cnt16, 1 ;[0] [6]
+ breq usbMFTime16 ;[2]
+ sbic USBIN, USBMINUS ;[3]
+ rjmp usbMFWaitStrobe ;[4]
+usbMFWaitIdle: ; then wait until idle again
+ sbis USBIN, USBMINUS ;1 wait for D- == 1
+ rjmp usbMFWaitIdle ;2
+ ldi cnt16L, 1 ;1 represents cycles so far
+ clr cnt16H ;1
+usbMFWaitLoop:
+ in cntH, USBIN ;[0] [7]
+ adiw cnt16, 1 ;[1]
+ breq usbMFTimeout ;[3]
+ andi cntH, USBMASK ;[4]
+ brne usbMFWaitLoop ;[5]
+usbMFTimeout:
+#if resL != cnt16L
+ mov resL, cnt16L
+ mov resH, cnt16H
+#endif
+ ret
+
+#undef resL
+#undef resH
+#undef cnt16
+#undef cnt16L
+#undef cnt16H
+#undef cntH
+
+#endif /* USB_CFG_HAVE_MEASURE_FRAME_LENGTH */
+
+
+#if USB_CFG_HAVE_MEASURE_FRAME_LENGTHx
#ifdef __IAR_SYSTEMS_ASM__
/* Register assignments for usbMeasureFrameLengthDecreasing on IAR cc */
/* Calling conventions on IAR:
@@ -350,6 +424,130 @@ usbDFWaitLoop:
#endif /* USB_CFG_HAVE_MEASURE_FRAME_LENGTH */
+
+
+#if USB_CFG_HAVE_MEASURE_FRAME_LENGTH
+#ifdef __IAR_SYSTEMS_ASM__
+/* Register assignments for usbMeasureFrameLengthDecreasing on IAR cc */
+/* Calling conventions on IAR:
+ * First parameter passed in r16/r17, second in r18/r19 and so on.
+ * Callee must preserve r4-r15, r24-r29 (r28/r29 is frame pointer)
+ * Result is passed in r16/r17
+ * In case of the "tiny" memory model, pointers are only 8 bit with no
+ * padding. We therefore pass argument 1 as "16 bit unsigned".
+ */
+
+# define resL r16
+# define resH r17
+# define cnt16L r30
+# define cnt16H r31
+# define cntH r18
+
+#else /* __IAR_SYSTEMS_ASM__ */
+/* Register assignments for usbMeasureFrameLength on gcc */
+/* Calling conventions on gcc:
+ * First parameter passed in r24/r25, second in r22/23 and so on.
+ * Callee must preserve r1-r17, r28/r29
+ * Result is passed in r24/r25
+ */
+
+# define i r20
+# define opV r19
+# define opD r18
+# define try r27
+# define stp r26
+# define cnt16L r24
+# define cnt16H r25
+#endif
+# define cnt16 cnt16L
+
+; extern void calibrateOscillatorASM(void);
+
+.global calibrateOscillatorASM
+calibrateOscillatorASM:
+
+ cli
+ ldi i, 10 ; 10 iterations
+
+ ldi opD, 255
+
+ ldi try, 128 ; calibration start value
+ ldi stp, 64 ; initial step width
+
+usbCOloop:
+
+ out OSCCAL, try
+ nop
+
+ ; Delay values = F_CPU * 999e-6 / 5 + 0.5
+
+#if (F_CPU == 16500000)
+ ldi cnt16L, lo8(3297)
+ ldi cnt16H, hi8(3297)
+#define usbok
+#endif
+
+#if (F_CPU == 12800000)
+ ldi cnt16L, lo8(2557)
+ ldi cnt16H, hi8(2557)
+#define usbok
+#endif
+
+#ifndef usbok
+ #error "calibrateOscillatorASM: no delayvalues defined for this F_CPU setting"
+#endif
+#undef usbok
+
+usbCOWaitStrobe: ; first wait for D- == 0 (idle strobe)
+ sbic USBIN, USBMINUS ;
+ rjmp usbCOWaitStrobe ;
+usbCOWaitIdle: ; then wait until idle again
+ sbis USBIN, USBMINUS ;1 wait for D- == 1
+ rjmp usbCOWaitIdle ;2
+usbCOWaitLoop:
+ sbiw cnt16,1 ;[0] [5]
+ sbic USBIN, USBMINUS ;[2]
+ rjmp usbCOWaitLoop ;[3]
+
+ sbrs cnt16H, 7 ;delay overflow?
+ rjmp usbCOclocktoolow
+ sub try, stp
+ neg cnt16L
+ rjmp usbCOclocktoohigh
+usbCOclocktoolow:
+ add try, stp
+usbCOclocktoohigh:
+ lsr stp
+ brne usbCOstepnotzero
+ cp opD, cnt16L
+ brcs usbCOnoimprovement
+ in opV, OSCCAL
+ mov opD, cnt16L
+usbCOnoimprovement:
+ ldi stp, 1
+usbCOstepnotzero:
+ subi i, 1
+ brne usbCOloop
+
+ out OSCCAL, opV
+ nop
+ sei
+ ret
+
+#undef i
+#undef opV
+#undef opD
+#undef try
+#undef stp
+#undef cnt16
+#undef cnt16L
+#undef cnt16H
+
+
+#endif /* USB_CFG_HAVE_MEASURE_FRAME_LENGTH */
+
+
+
;----------------------------------------------------------------------------
; Now include the clock rate specific code
;----------------------------------------------------------------------------