-
Notifications
You must be signed in to change notification settings - Fork 0
/
msp430usb.nim
165 lines (156 loc) · 5.23 KB
/
msp430usb.nim
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
import msp430, unsigned, tables
# Encodings requires local OS support. So it must be spawned as
# a separate staticExec of a native program. Yay.
#import encodings
#import marshal
{.pragma: usbram, codegenDecl: "$# __attribute__((section(\"usbram\"))) $#".}
type
index = int8
Request* = enum
GetStatus = 0
ClearFeature = 1
SetFeature = 3
SetAddress = 5
GetDescriptor = 6
SetDescriptor = 7
GetConfiguration = 8
SetConfiguration = 9
GetInterface = 10
SetInterface = 11
SynchFrame = 12
DescriptorType* = enum
dtDevice = 1
dtConfiguration = 2
dtString = 3
dtInterface = 4
dtEndpoint = 5
dtDeviceQualifier = 6
dtOtherSpeedConfiguration = 7
dtInterfacePower = 8
UsbDeviceRequest* = tuple
bmRequestType: uint8
bRequest: uint8
wValue: uint16
wIndex: uint16
wLength: uint16
UsbDeviceDescriptor* = tuple
bLength: uint8
bDescriptorType: uint8
bcdUSB: uint16
bDeviceClass: uint8
bDeviceSubClass: uint8
bDeviceProtocol: uint8
bMaxPacketSize0: uint8
idVendor: uint16
idProduct: uint16
bcdDevice: uint16
iManufacturer: index
iProduct: index
iSerialNumber: index
bNumConfigurations: int8
var
UsbSetupBlock {.extern:"USBSUBLK".} : UsbDeviceRequest
ep0inbuf {.extern:"USBIEP0BUF".} : array[0..7, uint8]
ep0outbuf {.extern:"USBOEP0BUF".} : array[0..7, uint8]
#ep1buf {.usbram.} : array[0..7, int8] # = [1i8,2,3,4,5,6,7,8]
newaddress : uint8 = 0x80
const
serial = staticExec("./toutf16", "MSP430 Joystick")
deviceDescriptor0 = (
bLength: 18, bDescriptorType: dtDevice, bcdUSB: 0x0310,
bDeviceClass: 0, bDeviceSubClass: 0, bDeviceProtocol: 0,
bMaxPacketSize0: 8, idVendor: 0x16c0, idProduct: 0x27dc, # V-USB HID Joystick, must set serial number text
bcdDevice: 0, iManufacturer: 0, iProduct: 0, iSerialNumber: 0, bNumConfigurations: 0)
descriptors = {(ord(dtDevice) shl 8) or 0: deviceDescriptor0,
#(ord(dtString) shl 8) or 0: serial,
}.toTable
ISR:
proc USB_UBM() =
if (USBIFG and SETUPIFG) != 0: # Setup packet
if UsbSetupBlock.bmRequestType shr 7 != 0: # in/out direction bit
USBCTL = USBCTL or DIR
else:
USBCTL = USBCTL and not cast[uint8](DIR)
case UsbSetupBlock.bmRequestType
of 0x80: # standard device in
case UsbSetupBlock.bRequest
of ord(SetAddress):
newaddress = UsbSetupBlock.wValue and 0xff
UsbIepCnt0 = 0
of ord(GetDescriptor):
#let desc = ref descriptors[UsbSetupBlock.wValue]
case UsbSetupBlock.wValue
of 0x0100: # device descriptor 0
discard # TODO: produce descriptor
else: discard
else: discard
else: discard
# Failure case: stall endpoint 0
USBIEPCNF_0 = USBIEPCNF_0 or STALL
USBOEPCNF_0 = USBOEPCNF_0 or STALL
while true:
# computedGoto does not seem to understand the values are all even
# {.computedGoto.}
case USBVECINT
of USBVECINT_NONE: return
#of USBVECINT_PWR_DROP:
#of USBVECINT_PLL_LOCK:
#of USBVECINT_PLL_SIGNAL:
#of USBVECINT_PLL_RANGE:
#of USBVECINT_PWR_VBUSOn:
#of USBVECINT_PWR_VBUSOff:
#of USBVECINT_USB_TIMESTAMP:
of USBVECINT_INPUT_ENDPOINT0:
if (newaddress and 0x80) == 0:
UsbFunAdr = newaddress
newaddress = newaddress or 0x80
of USBVECINT_OUTPUT_ENDPOINT0: discard
#of USBVECINT_RSTR: # reset - might want to auto-reset with FRSTE
#of USBVECINT_SUSR: # suspend
#of USBVECINT_RESR: # resume
of USBVECINT_SETUP_PACKET_RECEIVED: discard # Setup transaction, handled above
#of USBVECINT_STPOW_PACKET_RECEIVED: discard # should not happen, setup overwrite
#of USBVECINT_INPUT_ENDPOINT1:
#of USBVECINT_INPUT_ENDPOINT2:
#of USBVECINT_INPUT_ENDPOINT3:
#of USBVECINT_INPUT_ENDPOINT4:
#of USBVECINT_INPUT_ENDPOINT5:
#of USBVECINT_INPUT_ENDPOINT6:
#of USBVECINT_INPUT_ENDPOINT7:
#of USBVECINT_OUTPUT_ENDPOINT1:
#of USBVECINT_OUTPUT_ENDPOINT2:
#of USBVECINT_OUTPUT_ENDPOINT3:
#of USBVECINT_OUTPUT_ENDPOINT4:
#of USBVECINT_OUTPUT_ENDPOINT5:
#of USBVECINT_OUTPUT_ENDPOINT6:
#of USBVECINT_OUTPUT_ENDPOINT7:
else: discard
proc usbinit*() =
# Raise operating voltage to levels that permit USB
setVCoreUp 1
setVCoreUp 2
setVCoreUp 3
# Enable XT2 oscillator
enableXT2()
# Or USBKEYPID if you believe the manual.
UsbKeyID = cast[uint16](USBKEY) # enable USB configuration
# Configure USB PLL
# TODO: wait 2ms for capacitors to charge?
UsbPllCtl = cast[uint16](UPLLEN or UPFDEN)
UsbPllDivB = cast[uint16](UsbPll_setClk_val_4p0)
UsbPhyCtl = PUSEL # enable USB function of USB phy
# TODO: Wait 2ms and check PLL lock?
# Enable USB module and pull up resistor
USBCNF = USBCNF or cast[uint16](PUR_EN or USB_EN)
USBCTL = FEN or FRSTE
USBIE = SETUPIE
# Note: officially the resistor should not be enabled until PWR_VBUSOn
UsbKeyID = 0 # Lock configuration registers
# Clear endpoint 0 status
USBIEPCNF_0 = UBME or USBIIE
USBIEPCNT_0 = 0
USBOEPCNF_0 = UBME or USBIIE
USBOEPCNT_0 = 0
# Enable interrupts for endpoint 0
USBIEPIE = 1
USBOEPIE = 1