-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclient.py
More file actions
288 lines (213 loc) · 10.1 KB
/
client.py
File metadata and controls
288 lines (213 loc) · 10.1 KB
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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
import struct
import logging
from time import sleep
from threading import Thread
from wave_array.client.uart_protocol import UartProtocol
import numpy as np
# # Convert 16 bit 2s complement value to integer.
# def twoscomp16(raw):
# if raw & 0x8000:
# return raw - 0x10000
# else:
# return raw
logger = logging.getLogger(__name__)
class WaveArray:
# Register address map.
REG_RESET = 0x00000000
REG_FAULT = 0x00000001
REG_LED = 0x00000002
REG_VOICES = 0x00000003
REG_UNISON_MAX = 0x00000004
REG_ENVELOPE_N = 0x00000005
REG_LFO_N = 0x00000006
REG_MIDI_CHANNEL = 0x00000007
REG_DBG_WAVE_STATE_OFFLOAD = 0x00000100
REG_DBG_WAVE_STATE_SAMPLE = 0x00000101
REG_DBG_WAVE_FIFO = 0x00000102
REG_DBG_WAVE_TIMER = 0x00000103
REG_DBG_WAVE_FLAGS = 0x00000104
REG_DBG_UART_FLAGS = 0x00000110
REG_BINAURAL = 0x00000200
REG_UNISON_N = 0x00000201
REG_UNISON_SPREAD = 0x00000202
REG_NOISE_SELECT = 0x00000300
REG_FILTER_CUTOFF = 0x00000600
REG_FILTER_RESONANCE = 0x00000601
REG_FILTER_SELECT = 0x00000602 # Filter output select. 0 = LP, 1 = HP, 2 = BP, 3 = BS, 4 = bypass.
REG_DMA_BUSY = 0x00000700
REG_DMA_START_S2F = 0x00000701
REG_DMA_START_F2S = 0x00000702
REG_DMA_FLASH_ADDR_LO = 0x00000703
REG_DMA_FLASH_ADDR_HI = 0x00000704
REG_DMA_SDRAM_ADDR_LO = 0x00000705
REG_DMA_SDRAM_ADDR_HI = 0x00000706
REG_DMA_SECTOR_N = 0x00000707
REG_VOLUME_CTRL = 0x00000800
REG_HK_ENABLE = 0x00000900
REG_HK_PERIOD = 0x00000901
REG_WAVE_ENABLE = 0x00000902
REG_WAVE_PERIOD = 0x00000903
REG_QSPI_JEDEC_VENDOR = 0x00000A00
REG_QSPI_JEDEC_DEVICE = 0x00000A01
REG_QSPI_STATUS = 0x00000A02
REG_QSPI_CONFIG = 0x00000A03
REG_MOD_MAP_BASE = 0x00001000
REG_MOD_DEST_BASE = 0x00002000
REG_FRAME_CTRL_BASE = 0x00004000
REG_MIX_CTRL_BASE = 0x00005000
REG_FREQ_CTRL_BASE = 0x00006000
REG_TABLE_BASE = 0x00003000
REF_TABLE_ADDR_LOW = 0x00000000
REF_TABLE_ADDR_HIGH = 0x00000001
REF_TABLE_FRAMES = 0x00000002
REF_TABLE_UPDATE = 0x00000003
REG_ENVELOPE_CTRL_BASE = 0x00007000
REG_ENVELOPE_ATTACK = 0x00000000
REG_ENVELOPE_DECAY = 0x00000001
REG_ENVELOPE_SUSTAIN = 0x00000002
REG_ENVELOPE_RELEASE = 0x00000003
REG_ENVELOPE_LOOP = 0x00000004
REG_LFO_CTRL_BASE = 0x00008000
REG_LFO_VELOCITY = 0x00000000
REG_LFO_WAVE = 0x00000001
REG_LFO_TRIGGER = 0x00000002
REG_LFO_PHASE = 0x00000003
REG_LFO_ONESHOT = 0x00000004
REG_LFO_RESET = 0x00000005
REG_LFO_AMPLITUDE = 0x00000006
REG_LFO_BINAURAL = 0x00000007
REG_SH_CTRL_BASE = 0x00009000
REG_SH_VELOCITY = 0x00000000
REG_SH_AMPLITUDE = 0x00000001
REG_SH_SLEW = 0x00000002
REG_SH_INPUT = 0x00000003
REG_HARD_SYNC_BASE = 0x0000A000
REG_HARD_SYNC_ENABLE = 0x00000000
REG_HARD_SYNC_SOURCE = 0x00000001
def __init__(self, hk_signal=None, wave_signal=None, port='COM3'):
self.protocol = UartProtocol(port, 2_000_000, hk_signal, wave_signal)
# Disable HK and oscilloscope
self.write(WaveArray.REG_HK_ENABLE, 0)
self.write(WaveArray.REG_WAVE_ENABLE, 0)
# Stop HK to clear the input buffer.
# hk_enable = self.protocol.read(self.REG_HK_ENABLE)
# self.protocol.write(self.REG_HK_ENABLE, 0)
self.protocol.uart.uart.reset_input_buffer()
# self.protocol.write(self.REG_HK_ENABLE, hk_enable)
self.n_voices = self.protocol.read(self.REG_VOICES)
self.n_voices_log2 = int(np.ceil(np.log2(self.n_voices)))
def stop(self):
self.protocol.stop()
def reset(self):
self.protocol.write(self.REG_RESET, 0x01)
def set_led(self, enable):
self.protocol.write(self.REG_LED, int(enable))
def get_led(self):
return bool(self.protocol.read(self.REG_LED))
def read_faults(self):
return self.protocol.read(self.REG_FAULT)
def write(self, address, value):
# print(f'[{address:08X}] <= {value:04X}')
self.protocol.write(address, value)
def read(self, address, signed=False):
raw_value = self.protocol.read(address)
return np.int16(raw_value) if signed else np.uint16(raw_value)
def read_mod_source(self, destination, index):
address = self.REG_MOD_MAP_BASE + destination * 8 + index * 2
return self.read(address)
def write_mod_source(self, destination, index, source):
address = self.REG_MOD_MAP_BASE + destination * 8 + index * 2
# print(f'mod enable {destination} {index} {source} {address:08X}')
self.write(address, source)
def read_mod_amount(self, destination, index):
address = self.REG_MOD_MAP_BASE + destination * 8 + index * 2 + 1
return self.read(address, signed=True)
def write_mod_amount(self, destination, index, amount):
address = self.REG_MOD_MAP_BASE + destination * 8 + index * 2 + 1
self.write(address, amount)
def read_mod_dest(self, destination, voice):
address = self.REG_MOD_DEST_BASE + destination * 2**self.n_voices_log2 + voice
return self.read(address)
def write_sdram_bytes(self, address, data):
n_words = len(data) // 2
words = struct.unpack(f'>{n_words}h', data)
self.write_sdram_words(address, words)
def write_sdram_words(self, address, data):
# Stop HK during write.
hk_enable = self.protocol.read(self.REG_HK_ENABLE)
self.protocol.write(self.REG_HK_ENABLE, 0)
self.protocol.write_block(address, data)
self.protocol.write(self.REG_HK_ENABLE, hk_enable)
def read_sdram_bytes(self, address, length):
byteData = b''
words = self.read_sdram_words(address, length // 2).astype(np.uint16)
for w in words:
byteData += int(w >> 8).to_bytes(1, byteorder='big') + int(w & 0xFF).to_bytes(1, byteorder='big')
return byteData
def read_sdram_words(self, address, length):
# Stop HK during write.
hk_enable = self.protocol.read(self.REG_HK_ENABLE)
self.protocol.write(self.REG_HK_ENABLE, 0)
# Reads must be split into 1024 word block to avoid overflowing the uart fifo.
data = np.array([], dtype=np.int16)
while length > 0:
chunk = min(length, 1024)
data = np.concatenate((data, self.protocol.read_block(address, chunk)))
address += chunk
length -= chunk
self.protocol.write(self.REG_HK_ENABLE, hk_enable)
return data
def dma_flash_to_sdram(self, flash_address, sdram_address, sectors):
""" DMA FLASH to the SDRAM. """
logger.info(f'DMA {sectors} sectors from FLASH [0x{flash_address:08X}] to SDRAM [0x{sdram_address:08x}]')
self.write(WaveArray.REG_DMA_SECTOR_N, sectors)
self.write(WaveArray.REG_DMA_FLASH_ADDR_LO, flash_address & 0xFFFF)
self.write(WaveArray.REG_DMA_FLASH_ADDR_HI, (flash_address >> 16) & 0xFFFF)
self.write(WaveArray.REG_DMA_SDRAM_ADDR_LO, sdram_address & 0xFFFF)
self.write(WaveArray.REG_DMA_SDRAM_ADDR_HI, (sdram_address >> 16) & 0xFFFF)
self.write(WaveArray.REG_DMA_START_F2S, 1)
# Wait for DMA transfer to complete.
while self.read(WaveArray.REG_DMA_BUSY) != 0:
logger.debug('DMA F->S busy...')
sleep(0.1)
def dma_sdram_to_flash(self, sdram_address, flash_address, sectors):
""" DMA SDRAM to FLASH. """
logger.info(f'DMA {sectors} sectors from SDRAM [0x{sdram_address:08X}] to FLASH [0x{flash_address:08x}]')
self.write(WaveArray.REG_DMA_SECTOR_N, sectors)
self.write(WaveArray.REG_DMA_FLASH_ADDR_LO, flash_address & 0xFFFF)
self.write(WaveArray.REG_DMA_FLASH_ADDR_HI, (flash_address >> 16) & 0xFFFF)
self.write(WaveArray.REG_DMA_SDRAM_ADDR_LO, sdram_address & 0xFFFF)
self.write(WaveArray.REG_DMA_SDRAM_ADDR_HI, (sdram_address >> 16) & 0xFFFF)
self.write(WaveArray.REG_DMA_START_S2F, 1)
# Wait for DMA transfer to complete.
while self.read(WaveArray.REG_DMA_BUSY) != 0:
logger.debug('DMA S->F busy...')
sleep(0.1)
def main():
logging.basicConfig(level=logging.DEBUG)
log = logging.getLogger(__name__)
wave_array = WaveArray()
write_data_words = np.int16(list(range(1024)))
# write_data_words = np.int16([0x00] * 512)
# write_data_words = np.int16(list(range(512)) + [0x00] * 512)
log.info(f'data length = {len(write_data_words)}')
wave_array.write_sdram_words(0x8000, write_data_words)
log.info('sdram write complete')
wave_array.dma_sdram_to_flash(0x8000, 0x10000, 1)
wave_array.dma_flash_to_sdram(0x10000, 0x18000, 1)
read_data_words = wave_array.read_sdram_words(0x18000, len(write_data_words))
log.info('sdram read complete')
for i, (wdata, rdata) in enumerate(zip(write_data_words, read_data_words)):
if wdata != rdata:
log.error(f'{i:4d} {wdata} != {rdata}')
exit()
# write_data_bytes = bytes(list(range(256)) * 4)
# # write_data_bytes = bytes([0] * 1024)
# print('write_data_bytes:', write_data_bytes)
# wave_array.write_sdram_bytes(0, write_data_bytes)
# wave_array.dma_sdram_to_flash(0, 0, 1)
# wave_array.dma_flash_to_sdram(0, 0, 1)
# read_data_bytes = wave_array.read_sdram_bytes(0, 1024)
# print('read_data_bytes:', read_data_bytes)
if __name__ == '__main__':
main()