forked from ArminJo/micronucleus-firmware
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathosccal.S
67 lines (59 loc) · 1.88 KB
/
osccal.S
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
; Ralph Doncaster 2020
; optimized OSCCAL tuning from low-speed USB SOF every 1ms
#include "macros.inc"
#define __SFR_OFFSET 0 /* start SFRs at 0x00 not 0x20 */
#include "usbdrv/usbdrv.h"
/*
; defines for standalone debugging
#define OSCCAL 0x31
#define USBIN 0x16
#define USBPLUS 4
#define USBMINUS 3
*/
#define countH r25
#define countL r24
#define scratch r23
#define shift r22
; tuneOsccal should be called after USB reset
; needs to see 5 consecutive EOF/SOF transistions
GLABEL tuneOsccal
reset:
sbis USBIN, USBMINUS
rjmp reset ; wait for bus reset to end
;sts NRDR, r1 ; debug
rcall countFrame ; ignore 1st count
rcall countFrame
rcall tuneOnce
rcall tuneOnce
; fall through to tuneOnce for third time
.equ fKHz, (F_CPU/1000)
.equ goal, (fKHz / 12) * fraction ; each fraction is 12 cycles
tuneOnce:
subi countH, hi8(goal) ; countH-goal = change to OSCCAL
LOAD scratch, OSCCAL
sub scratch, countH
STORE OSCCAL, scratch
;sts NRDR, countH ; debug
; fall through to countFrame for next tuning
; countFrame counts the time to the next EOF/SOF
; end-of-frame has an idle guard band followed by SE0 (D+ & D- low)
; idle is D+ low & D- high. save D+ history in shift
; countL is used as a fractional accumulator with countH LSbit =~ 0.5%
; fraction = (256/.5)/fMHz rounded
.equ fraction, ((2 * 512)/(fKHz / 1000) + 1) / 2
countFrame:
ldi shift, 0xFF
ldi countL, fraction ; countFrame overhead adjustment
clr countH
waitSOF: ; 12-cycle loop
lsr shift
in scratch, USBIN
or scratch, r0
adiw countL, fraction
bst scratch, USBPLUS
bld shift, 7
in r0, USBIN
sbrs r0, USBMINUS
tst shift
brne waitSOF ; not idle last 7 loops
ret