Ver código fonte

Updates for initial timer and pwm test on piccadae.

master
kevin.larke 4 anos atrás
pai
commit
de586ca2e3

+ 270
- 0
control/app/picadae_api.py Ver arquivo

@@ -0,0 +1,270 @@
1
+import os,sys,argparse,yaml,types,select,serial,logging,time,datetime
2
+from enum import Enum
3
+from multiprocessing import Process, Pipe
4
+
5
+# Message header id's for messages passed between the application
6
+# process and the microcontroller and video processes
7
+
8
+TinyOpD = {
9
+    'setPwmOp':     0,
10
+    'noteOnVelOp':  1,
11
+    'noteOnUsecOp': 2,
12
+    'noteOffOp':    3,
13
+    'readOp':       4,
14
+    'writeOp':      5
15
+}
16
+
17
+class TinyRegAddr(Enum):
18
+    kRdRegAddrAddr   =  0,
19
+    kRdTableAddrAddr =  1,
20
+    kRdEEAddrAddr    =  2,
21
+    kRdSrcAddr       =  3,
22
+    kWrRegAddrAddr   =  4,
23
+    kWrTableAddrAddr =  5,
24
+    kWrEEAddrAddr    =  6,
25
+    kWrDstAddr       =  7,
26
+    kTmrCoarseAddr   =  8,
27
+    kTmrFineAddr     =  9,
28
+    kTmrPrescaleAddr = 10, 
29
+    kPwmEnableAddr   = 11,
30
+    kPwmDutyAddr     = 12,
31
+    kPwmFreqAddr     = 13,
32
+    kModeAddr        = 14,
33
+    kStateAddr       = 15,
34
+    kErrorCodeAddr   = 16
35
+
36
+class TinyConst(Enum):
37
+    kRdRegSrcId    = TinyRegAddr.kRdRegAddrAddr,    # 0
38
+    kRdTableSrcId  = TinyRegAddr.kRdTableAddrAddr,  # 1
39
+    kRdEESrcId     = TinyRegAddr.kRdEEAddrAddr      # 2
40
+    
41
+    kWrRegDstId    = TinyRegAddr.kWrRegAddrAddr,    # 4
42
+    kWrTableDstId  = TinyRegAddr.kWrTableAddrAddr,  # 5
43
+    kWrEEDstId     = TinyRegAddr.kWrEEAddrAddr,     # 6
44
+    kWrAddrFl      = 0x08,                          # first avail bit above kWrEEAddr
45
+    
46
+class SerialMsgId(Enum):
47
+    QUIT_MSG   = 0xffff   
48
+    DATA_MSG   = 0xfffe
49
+
50
+
51
+def _serial_process_func( serial_dev, baud, pipe ):
52
+
53
+    reset_N     = 0
54
+    drop_N      = 0
55
+    noSync_N    = 0
56
+    
57
+    with serial.Serial(serial_dev, baud) as port:
58
+
59
+        while True:
60
+
61
+            # get the count of available bytes in the serial port buffer
62
+            bytes_waiting_N = port.in_waiting
63
+
64
+
65
+            # if no serial port bytes are available then sleep ....
66
+            if bytes_waiting_N == 0:                    
67
+                time.sleep(0.01)  # ... for 10 ms
68
+
69
+            else: # read the serial port ...
70
+                v = port.read(bytes_waiting_N)
71
+
72
+                pipe.send((SerialMsgId.DATA_MSG,v)) # ... and send it to the parent
73
+                            
74
+            
75
+            msg = None
76
+            if pipe.poll():  # non-blocking check for parent process messages
77
+                try:
78
+                    msg = pipe.recv()
79
+                except EOFError:
80
+                    break
81
+                
82
+            # if an incoming message was received
83
+            if msg != None:
84
+
85
+                # this is a shutdown msg
86
+                if msg[0] == SerialMsgId.QUIT_MSG:
87
+                    pipe.send(msg) # ... send quit msg back
88
+                    break
89
+
90
+                # this is a data xmit msg
91
+                elif msg[0] == SerialMsgId.DATA_MSG:
92
+                    port.write(msg[1])
93
+                
94
+
95
+
96
+
97
+
98
+class SerialProcess(Process):
99
+    def __init__(self,serial_dev,serial_baud):
100
+        self.parent_end, child_end = Pipe()
101
+        super(SerialProcess, self).__init__(target=_serial_process_func, name="Serial", args=(serial_dev,serial_baud,child_end,))
102
+        self.doneFl    = False
103
+        
104
+    def quit(self):
105
+        # send quit msg to the child process
106
+        self.parent_end.send((SerialMsgId.QUIT_MSG,0))
107
+
108
+    def send(self,msg_id,value):
109
+        # send a msg to the child process
110
+        self.parent_end.send((msg_id,value))
111
+
112
+    def recv(self):
113
+        # 
114
+        
115
+        x = None
116
+        if not self.doneFl and self.parent_end.poll():
117
+            x = self.parent_end.recv()
118
+            
119
+            if x[0] == SerialMsgId.QUIT_MSG:
120
+                self.doneFl = True
121
+            
122
+        return x
123
+    
124
+    def is_done(self):
125
+        return self.doneFl
126
+
127
+        
128
+
129
+class Picadae:
130
+    def __init__( self, key_mapL, i2c_base_addr=1, serial_dev='/dev/ttyACM0', serial_baud=38400 ):
131
+        """
132
+        key_mapL      = [{ index, board, ch, type, midi, class }]  
133
+        serial_dev    = /dev/ttyACM0
134
+        serial_baud   = 38400
135
+        i2c_base_addr = 1
136
+        """        
137
+        self.serialProc     = SerialProcess( serial_dev, serial_baud )
138
+        self.keyMapD        = { d['midi']:d for d in key_mapL }
139
+        self.i2c_base_addr  = i2c_base_addr
140
+        self.prescaler_usec = 32
141
+        
142
+        self.serialProc.start()
143
+        
144
+    def close( self ):
145
+        self.serialProc.quit()
146
+        
147
+    def write( self, i2c_addr, reg_addr, byteL ):
148
+        return self._send( 'w', i2c_addr, reg_addr, [ len(byteL) ] + byteL )
149
+
150
+    def set_read_addr( self, i2c_addr, src, addr ):
151
+        return self. write(i2c_addr, TinyOpD['readOp'], src, addr )
152
+            
153
+    def set_reg_read_addr( self, i2c_addr, addr ):
154
+        return self.set_read_addr(i2c_addr, TinyRegAddr.kRdRegAddrAddr, addr )
155
+
156
+    def set_table_read_addr( self, i2c_addr, addr ):
157
+        return self.set_read_addr(i2c_addr, TinyRegAddr.kRdTableAddrAddr, addr )
158
+    
159
+    def set_eeprom_read_addr( self, i2c_addr, addr ):
160
+        return self.set_read_addr(i2c_addr, TinyRegAddr.kRdEEAddrAddr, addr )
161
+    
162
+    def read_request( self, i2c_addr, reg_addr, argL ):
163
+        return self._send( 'r', i2c_addr, reg_addr,    [  byteOutN, len(argL) ] + argL )
164
+
165
+    def read_poll( self ):
166
+        return self.serialProc.recv()
167
+
168
+    def read_block( self, i2c_addr, reg_addr, argL, byteOutN, time_out_ms ):
169
+        
170
+        self.read_request( self, i2c_addr, reg_addr, argL, byteOutN )
171
+
172
+        ts = datetime.datetime.now() + datetime.timeDelta(milliseconds=time_out_ms)
173
+
174
+        retL = []
175
+        while datetime.datetime.now() < ts and len(retL) < byteOutN:
176
+            
177
+            x = self.serialProc.recv()
178
+            if x is not None:
179
+                retL.append(x)
180
+            
181
+            time.sleep(0.01)
182
+        
183
+        return retL
184
+        
185
+
186
+    def note_on_vel( self, midi_pitch, midi_vel ):
187
+        return self.write( self._pitch_to_i2c_addr( midi_pitch ),
188
+                           TinyOpD['noteOnVelOp'],
189
+                           [self._validate_vel(midi_vel)] )
190
+    
191
+    def note_on_us( self, midi_pitch, pulse_usec ):
192
+        return self.write( self._pitch_to_i2c_addr( midi_pitch ),
193
+                           TinyOpD['noteOnUsecOp'],
194
+                           list(self._usec_to_coarse_and_fine(pulse_usec)) )
195
+
196
+    def note_off( self, midi_pitch ):
197
+        return self.write( self._pitch_to_i2c_addr( midi_pitch ),
198
+                           TinyOpD['noteOffOp'],[0] )  # TODO: sending a dummy byte because we can handle sending a command with no data bytes.
199
+
200
+    def set_velocity_map( self, midi_pitch, midi_vel, pulse_usec ):
201
+        pass
202
+    
203
+    def get_velocity_map( self, midi_pitch, midi_vel, time_out_ms=250 ):
204
+        pass
205
+    
206
+    def set_pwm_duty( self, midi_pitch, duty_cycle_pct, enableFl=True ):
207
+        return self.write( self._pitch_to_i2c_addr( midi_pitch ),
208
+                           TinyOpD['setPwmOp'],
209
+                           [enableFl, int( duty_cycle_pct * 255.0 /100.0 )])
210
+
211
+    def get_pwm_duty( self, midi_pitch, time_out_ms=250 ):
212
+        return self.read_block( self._pitch_to_i2c_addr( midi_pitch ),
213
+                                TinyRegAddr.kPwmDutyAddr,
214
+                                [], 1, time_out_ms )
215
+    
216
+    def set_pwm_freq( self, midi_pitch, freq_div_id ):
217
+        # pwm frequency divider 1=1,2=8,3=64,4=256,5=1024
218
+        assert( 1 <= freq_div_id and freq_div_id <= 5 )
219
+        pass
220
+    
221
+    def get_pwm_freq( self, midi_pitch, time_out_ms=250 ):
222
+        return self.read_block( self._pitch_to_i2c_addr( midi_pitch ),
223
+                                TinyRegAddr.kPwmFreqAddr,
224
+                                [], 1, time_out_ms )
225
+
226
+    def set_flags( self, midi_pitch, flags ):
227
+        return self.write( self._pitch_to_i2c_addr( midi_pitch ),                           
228
+                           TinyOpD['writeOp'],
229
+                           [ 12, 14, flags ])
230
+
231
+    def make_note( self, midi_pitch, atk_us, dur_ms ):
232
+        # TODO: handle error on note_on_us()
233
+        self.note_on_us(midi_pitch, atk_us);
234
+        time.sleep( dur_ms / 1000.0 )
235
+        return self.note_off(midi_pitch)
236
+        
237
+    def _pitch_to_i2c_addr( self, pitch ):
238
+        return self.keyMapD[ pitch ]['index'] + self.i2c_base_addr
239
+
240
+    def _validate_vel( self, vel ):
241
+        return vel
242
+
243
+    def _usec_to_coarse_and_fine( self, usec ):
244
+        
245
+        coarse = int( usec / (self.prescaler_usec*255))
246
+        fine   = int((usec - coarse*self.prescaler_usec*255) / self.prescaler_usec)
247
+
248
+        print(coarse,fine)
249
+        assert( coarse <= 255 )
250
+        assert( fine <= 255)
251
+
252
+        return coarse,fine
253
+
254
+    def _send( self, opcode, i2c_addr, reg_addr, byteL  ):
255
+
256
+        self._print( opcode, i2c_addr, reg_addr, byteL )
257
+        
258
+        byteA = bytearray( [ord(opcode), i2c_addr, reg_addr ] + byteL )
259
+
260
+        return self.serialProc.send(SerialMsgId.DATA_MSG, byteA )
261
+
262
+    def _print( self, opcode, i2c_addr, reg_addr, byteL ):
263
+        
264
+        s = "{} {} {}".format( opcode, i2c_addr, reg_addr )
265
+
266
+        for x in byteL:
267
+            s += " {}".format(x)
268
+
269
+
270
+        print(s)

+ 102
- 0
control/app/picadae_cmd.yml Ver arquivo

@@ -3,6 +3,108 @@
3 3
    {
4 4
      serial_dev: "/dev/ttyACM0",
5 5
      serial_baud: 38400,
6
+     i2c_base_addr: 21,
7
+     prescaler_usec: 32,
8
+     
9
+     key_mapL: [
10
+
11
+       { index: 0, board: 1, ch:  1, type: 'wB', midi: 21, class: 'A' },
12
+       { index: 1, board: 1, ch:  2, type: 'Bl', midi: 22, class: 'A#' },
13
+       { index: 2, board: 1, ch:  3, type: 'wF', midi: 23, class: 'B' },
14
+       { index: 3, board: 1, ch:  4, type: 'wB', midi: 24, class: 'C' },
15
+       { index: 4, board: 1, ch:  5, type: 'Bl', midi: 25, class: 'C#' },
16
+       { index: 5, board: 1, ch:  6, type: 'wF', midi: 26, class: 'D' },
17
+       { index: 6, board: 1, ch:  7, type: 'Bl', midi: 27, class: 'D#' },
18
+       { index: 7, board: 1, ch:  8, type: 'wB', midi: 28, class: 'E' },
19
+       { index: 8, board: 1, ch:  9, type: 'wF', midi: 29, class: 'F' },
20
+       { index: 9, board: 1, ch: 10, type: 'Bl', midi: 30, class: 'F#' },
21
+       { index: 10, board: 1, ch: 11, type: 'wB', midi: 31, class: 'G' },
22
+
23
+       { index: 11, board: 2, ch:  1, type: 'Bl', midi: 32, class: 'G#' },
24
+       { index: 12, board: 2, ch:  2, type: 'wF', midi: 33, class: 'A' },
25
+       { index: 13, board: 2, ch:  3, type: 'Bl', midi: 34, class: 'A#' },
26
+       { index: 14, board: 2, ch:  4, type: 'wB', midi: 35, class: 'B' },
27
+       { index: 15, board: 2, ch:  5, type: 'wF', midi: 36, class: 'C' },
28
+       { index: 16, board: 2, ch:  6, type: 'Bl', midi: 37, class: 'C#' },
29
+       { index: 17, board: 2, ch:  7, type: 'wB', midi: 38, class: 'D' },
30
+       { index: 18, board: 2, ch:  8, type: 'Bl', midi: 39, class: 'D#' },
31
+       { index: 19, board: 2, ch:  9, type: 'wF', midi: 40, class: 'E' },
32
+       { index: 20, board: 2, ch: 10, type: 'wB', midi: 41, class: 'F' },
33
+       { index: 21, board: 2, ch: 11, type: 'Bl', midi: 42, class: 'F#' },
34
+
35
+       { index: 22, board: 3, ch:  1, type: 'wF', midi: 43, class: 'G' },
36
+       { index: 23, board: 3, ch:  2, type: 'Bl', midi: 44, class: 'G#' },
37
+       { index: 24, board: 3, ch:  3, type: 'wB', midi: 45, class: 'A' },
38
+       { index: 25, board: 3, ch:  4, type: 'Bl', midi: 46, class: 'A#' },
39
+       { index: 26, board: 3, ch:  5, type: 'wF', midi: 47, class: 'B' },
40
+       { index: 27, board: 3, ch:  6, type: 'wB', midi: 48, class: 'C' },
41
+       { index: 28, board: 3, ch:  7, type: 'Bl', midi: 49, class: 'C#' },
42
+       { index: 29, board: 3, ch:  8, type: 'wF', midi: 50, class: 'D' },
43
+       { index: 30, board: 3, ch:  9, type: 'Bl', midi: 51, class: 'D#' },
44
+       { index: 31, board: 3, ch: 10, type: 'wB', midi: 52, class: 'E' },
45
+       { index: 32, board: 3, ch: 11, type: 'wF', midi: 53, class: 'F' },
46
+
47
+       { index: 33, board: 4, ch:  1, type: 'Bl', midi: 54, class: 'F#' },
48
+       { index: 34, board: 4, ch:  2, type: 'wB', midi: 55, class: 'G' },
49
+       { index: 35, board: 4, ch:  3, type: 'Bl', midi: 56, class: 'G#' },
50
+       { index: 36, board: 4, ch:  4, type: 'wF', midi: 57, class: 'A' },
51
+       { index: 37, board: 4, ch:  5, type: 'Bl', midi: 58, class: 'A#' },
52
+       { index: 38, board: 4, ch:  6, type: 'wB', midi: 59, class: 'B' },
53
+       { index: 39, board: 4, ch:  7, type: 'wF', midi: 60, class: 'C' },
54
+       { index: 40, board: 4, ch:  8, type: 'Bl', midi: 61, class: 'C#' },
55
+       { index: 41, board: 4, ch:  9, type: 'wB', midi: 62, class: 'D' },
56
+       { index: 42, board: 4, ch: 10, type: 'Bl', midi: 63, class: 'D#' },
57
+       { index: 43, board: 4, ch: 11, type: 'wF', midi: 64, class: 'E' },
58
+
59
+       { index: 44, board: 5, ch:  1, type: 'wB', midi: 65, class: 'F' },
60
+       { index: 45, board: 5, ch:  2, type: 'Bl', midi: 66, class: 'F#' },
61
+       { index: 46, board: 5, ch:  3, type: 'wF', midi: 67, class: 'G' },
62
+       { index: 47, board: 5, ch:  4, type: 'Bl', midi: 68, class: 'G#' },
63
+       { index: 48, board: 5, ch:  5, type: 'wB', midi: 69, class: 'A' },
64
+       { index: 49, board: 5, ch:  6, type: 'Bl', midi: 70, class: 'A#' },
65
+       { index: 50, board: 5, ch:  7, type: 'wF', midi: 71, class: 'B' },
66
+       { index: 51, board: 5, ch:  8, type: 'wB', midi: 72, class: 'C' },
67
+       { index: 52, board: 5, ch:  9, type: 'Bl', midi: 73, class: 'C#' },
68
+       { index: 53, board: 5, ch: 10, type: 'wF', midi: 74, class: 'D' },
69
+       { index: 54, board: 5, ch: 11, type: 'Bl', midi: 75, class: 'D#' },
70
+
71
+       { index: 55, board: 6, ch:  1, type: 'wB', midi: 76, class: 'E' },
72
+       { index: 56, board: 6, ch:  2, type: 'wF', midi: 77, class: 'F' },
73
+       { index: 57, board: 6, ch:  3, type: 'Bl', midi: 78, class: 'F#' },
74
+       { index: 58, board: 6, ch:  4, type: 'wB', midi: 79, class: 'G' },
75
+       { index: 59, board: 6, ch:  5, type: 'Bl', midi: 80, class: 'G#' },
76
+       { index: 60, board: 6, ch:  6, type: 'wF', midi: 81, class: 'A' },
77
+       { index: 61, board: 6, ch:  7, type: 'Bl', midi: 82, class: 'A#' },
78
+       { index: 62, board: 6, ch:  8, type: 'wB', midi: 83, class: 'B' },
79
+       { index: 63, board: 6, ch:  9, type: 'wF', midi: 84, class: 'C' },
80
+       { index: 64, board: 6, ch: 10, type: 'Bl', midi: 85, class: 'C#' },
81
+       { index: 65, board: 6, ch: 11, type: 'wB', midi: 86, class: 'D' },
82
+
83
+       { index: 66, board: 6, ch:  1, type: 'Bl', midi: 87, class: 'D#' },
84
+       { index: 67, board: 6, ch:  2, type: 'wF', midi: 88, class: 'E' },
85
+       { index: 68, board: 6, ch:  3, type: 'wB', midi: 89, class: 'F' },
86
+       { index: 69, board: 6, ch:  4, type: 'Bl', midi: 90, class: 'F#' },
87
+       { index: 70, board: 6, ch:  5, type: 'wF', midi: 91, class: 'G' },
88
+       { index: 71, board: 6, ch:  6, type: 'Bl', midi: 92, class: 'G#' },
89
+       { index: 72, board: 6, ch:  7, type: 'wB', midi: 93, class: 'A' },
90
+       { index: 73, board: 6, ch:  8, type: 'Bl', midi: 94, class: 'A#' },
91
+       { index: 74, board: 6, ch:  9, type: 'wF', midi: 95, class: 'B' },
92
+       { index: 75, board: 6, ch: 10, type: 'wB', midi: 96, class: 'C' },
93
+       { index: 76, board: 6, ch: 11, type: 'Bl', midi: 97, class: 'C#' },
94
+       
95
+       { index: 77, board: 7, ch:  1, type: 'wF', midi: 98,  class: 'D' },
96
+       { index: 78, board: 7, ch:  2, type: 'Bl', midi: 99,  class: 'D#' },
97
+       { index: 79, board: 7, ch:  3, type: 'wB', midi: 100, class: 'E' },
98
+       { index: 80, board: 7, ch:  4, type: 'wF', midi: 101, class: 'F' },
99
+       { index: 81, board: 7, ch:  5, type: 'Bl', midi: 102, class: 'F#' },
100
+       { index: 82, board: 7, ch:  6, type: 'wB', midi: 103, class: 'G' },
101
+       { index: 83, board: 7, ch:  7, type: 'Bl', midi: 104, class: 'G#' },
102
+       { index: 84, board: 7, ch:  8, type: 'wF', midi: 105, class: 'A' },
103
+       { index: 85, board: 7, ch:  9, type: 'Bl', midi: 106, class: 'A#' },
104
+       { index: 86, board: 7, ch: 10, type: 'wB', midi: 107, class: 'B' },
105
+       { index: 87, board: 7, ch: 11, type: 'wF', midi: 108, class: 'C' },
106
+
107
+       ]
6 108
      
7 109
    }
8 110
 }

+ 169
- 0
control/app/picadae_shell.py Ver arquivo

@@ -0,0 +1,169 @@
1
+import os,sys,argparse,yaml,types,select,serial,logging,time
2
+
3
+from picadae_api import Picadae
4
+
5
+class PicadaeShell:
6
+    def __init__( self, cfg ):
7
+        self.p      = None
8
+        self.parseD = {
9
+            'q':{ "func":None,           "varN":0,  "help":"quit"},
10
+            '?':{ "func":"help",         "varN":0,  "help":"Print usage text."},
11
+            'w':{ "func":"write",        "varN":-1, "help":"write <i2c_addr> <reg_addr> <data0> ... <dataN>"},
12
+            'r':{ "func":"read",         "varN":3,  "help":"read  <i2c_addr> <reg_addr> <byteN>"},
13
+            'v':{ "func":"note_on_vel",  "varN":2,  "help":"note-on <pitch> <vel>"},
14
+            'u':{ "func":"note_on_us",   "varN":2,  "help":"note-on <pitch> <usec>"},
15
+            'o':{ "func":"note_off",     "varN":1,  "help":"note-off <pitch>"},
16
+            'T':{ "func":"set_vel_map",  "varN":3,  "help":"table <pitch> <vel> <usec>"},
17
+            't':{ "func":"get_vel_map",  "varN":2,  "help":"table <pitch> <vel>"},
18
+            'D':{ "func":"set_pwm_duty", "varN":2,  "help":"duty <pitch> <percent>"},
19
+            'd':{ "func":"get_pwm_duty", "varN":1,  "help":"duty <pitch>"},
20
+            'F':{ "func":"set_pwm_freq", "varN":2,  "help":"freq <pitch> <hz>"},
21
+            'f':{ "func":"get_pwm_freq", "varN":1,  "help":"freq <pitch>"},
22
+            'B':{ "func":"set_flags",    "varN":2,  "help":"flags <pitch> <flags>"},
23
+            'N':{ "func":"make_note",    "varN":3,  "help":"note <pitch> atkUs durMs"},
24
+            }
25
+
26
+    def _do_help( self, _ ):
27
+        for k,d in self.parseD.items():
28
+            s = "{} = {}".format( k, d['help'] )
29
+            print(s)
30
+
31
+    def _do_write( self, argL ):
32
+        return self.p.write(argL[0], argL[1], argL[2:])
33
+    
34
+    def _do_read( self, argL ):
35
+        return self.p.read(*argL)
36
+
37
+    def _do_note_on_vel( self, argL ):
38
+        return self.p.note_on_vel(*argL)
39
+    
40
+    def _do_note_on_us( self, argL ):
41
+        return self.p.note_on_us(*argL)
42
+
43
+    def _do_note_off( self, argL ):
44
+        return self.p.note_off(*argL)
45
+
46
+    def _do_set_vel_map( self, argL ):
47
+        return self.p.set_velocity_map(*argL)
48
+
49
+    def _do_get_vel_map( self, argL ):
50
+        return self.p.get_velocity_map(*argL)
51
+
52
+    def _do_set_pwm_duty( self, argL ):
53
+        return self.p.set_pwm_duty(*argL)
54
+
55
+    def _do_get_pwm_duty( self, argL ):
56
+        return self.p.get_pwm_duty(*argL)
57
+    
58
+    def _do_set_pwm_freq( self, argL ):
59
+        return self.p.set_pwm_freq(*argL)
60
+
61
+    def _do_get_pwm_freq( self, argL ):
62
+        return self.p.get_pwm_freq(*argL)
63
+
64
+    def _do_set_flags( self, argL ):
65
+        return self.p.set_flags(*argL)
66
+
67
+    def _do_make_note( self, argL ):
68
+        return self.p.make_note(*argL)
69
+        
70
+    def _syntaxError( self, msg ):
71
+        print("Syntax Error: " + msg )
72
+        return None
73
+            
74
+    def _exec_cmd( self, tokL ):
75
+        if len(tokL) <= 0:
76
+            return None
77
+
78
+        opcode = tokL[0]
79
+        
80
+        if opcode not in self.parseD:
81
+            return self._syntaxError("Unknown opcode: '{}'.".format(opcode))
82
+
83
+        d = self.parseD[ opcode ]
84
+
85
+        func_name = "_do_" + d['func']
86
+
87
+        if hasattr(self, func_name ):
88
+            func   = getattr(self, func_name )
89
+
90
+            try:
91
+                argL = [ int(tokL[i]) for i in range(1,len(tokL)) ]
92
+            except:
93
+                return self._syntaxError("Unable to create integer arguments.")
94
+
95
+            if  d['varN'] != -1 and len(argL) != d['varN']:                
96
+                return self._syntaxError("Argument mismatch {} != {}.".format(len(argL),d['varN']))
97
+            
98
+            result = func(argL) 
99
+
100
+        return None
101
+    
102
+    def run( self ):
103
+
104
+        # create the API object
105
+        self.p = Picadae( cfg.key_mapL, cfg.i2c_base_addr, cfg.serial_dev, cfg.serial_baud )
106
+
107
+        print("'q'=quit '?'=help")
108
+        time_out_secs = 1
109
+        
110
+        while True:
111
+
112
+            # wait for keyboard activity
113
+            i, o, e = select.select( [sys.stdin], [], [], time_out_secs )
114
+
115
+            if (i):
116
+                # read the command
117
+                s = sys.stdin.readline().strip() 
118
+
119
+                # tokenize the command
120
+                tokL = s.split(' ')
121
+
122
+                # if this is the 'quit' command
123
+                if tokL[0] == 'q':
124
+                    break
125
+
126
+                # execute the command
127
+                self._exec_cmd( tokL )
128
+                
129
+                
130
+        self.p.close()
131
+    
132
+def parse_args():
133
+    """Parse the command line arguments."""
134
+    
135
+    descStr  = """Picadae auto-calibrate."""
136
+    logL     = ['debug','info','warning','error','critical']
137
+    
138
+    ap = argparse.ArgumentParser(description=descStr)
139
+
140
+
141
+    ap.add_argument("-s","--setup",                     default="picadae_cmd.yml",  help="YAML configuration file.")
142
+    ap.add_argument("-c","--cmd",   nargs="*",                                   help="Give a command as multiple tokens")
143
+    ap.add_argument("-r","--run",                                                help="Run a named command list from the setup file.")
144
+    ap.add_argument("-l","--log_level",choices=logL,     default="warning",      help="Set logging level: debug,info,warning,error,critical. Default:warning")
145
+
146
+    return ap.parse_args()
147
+    
148
+            
149
+def parse_yaml_cfg( fn ):
150
+    """Parse the YAML configuration file."""
151
+    
152
+    cfg  = None
153
+    
154
+    with open(fn,"r") as f:
155
+        cfgD = yaml.load(f, Loader=yaml.FullLoader)
156
+
157
+        cfg = types.SimpleNamespace(**cfgD['picadae_cmd'])
158
+
159
+    return cfg
160
+
161
+if __name__ == "__main__":
162
+
163
+    args = parse_args()
164
+
165
+    cfg = parse_yaml_cfg( args.setup )
166
+
167
+    app = PicadaeShell(cfg)
168
+
169
+    app.run()

+ 9
- 3
control/ctrl/main.c Ver arquivo

@@ -78,12 +78,12 @@ void i2c_read_from( uint8_t i2c_addr, uint8_t dev_reg_addr, uint8_t read_byte_cn
78 78
   // Request to read from the client. Note that 'sendStop'==0.
79 79
   // Use this call to tell the client what data should be sent
80 80
   // during the subsequent twi_readFrom().
81
-  twi_writeTo(I2C_REMOTE_ADDR, &dev_reg_addr, 1, kWaitFl, kNoSendStopFl);
81
+  twi_writeTo(i2c_addr, &dev_reg_addr, 1, kWaitFl, kNoSendStopFl);
82 82
 
83 83
       
84 84
   // Blocking waiting and wait to read the client's response.
85 85
   for( uint8_t i=0; i<read_byte_cnt; ++i)
86
-    if( twi_readFrom(I2C_REMOTE_ADDR, &recv_char, 1, i==read_byte_cnt-1) )
86
+    if( twi_readFrom(i2c_addr, &recv_char, 1, i==read_byte_cnt-1) )
87 87
       uart_putchar(recv_char);
88 88
 
89 89
   PORTB ^= _BV(PORTB5);   //  toggle LED
@@ -217,6 +217,7 @@ int main (void)
217 217
           }
218 218
           else
219 219
           {
220
+            // TODO: handle case where there are no data bytes (only e.g. note-off)
220 221
             state = kWait_for_value;
221 222
             data_buf[0] = dev_reg_addr; // make 'dev_reg_addr' the first data value to write
222 223
             data_buf_idx = 1;           // 
@@ -237,8 +238,13 @@ int main (void)
237 238
           
238 239
             if(data_buf_idx == op_byte_cnt )
239 240
             {
241
+              /*
242
+              uint8_t ii;
243
+              for(ii=0; ii<op_byte_cnt; ++ii)
244
+                uart_putchar( data_buf[ii] );
245
+              */
240 246
               
241
-              i2c_xmit( I2C_REMOTE_ADDR, data_buf, op_byte_cnt, kSendStopFl);
247
+              i2c_xmit( i2c_addr, data_buf, op_byte_cnt, kSendStopFl);
242 248
               state = kWait_for_cmd;
243 249
             }
244 250
           }

+ 5
- 1
control/tiny/Makefile Ver arquivo

@@ -1,3 +1,7 @@
1
+#
2
+# Usage: make I2C_ADDR=8
3
+#
4
+
1 5
 ifndef TTY
2 6
 TTY=/dev/ttyACM0
3 7
 endif
@@ -9,7 +13,7 @@ endif
9 13
 MCU=attiny85
10 14
 AVRDUDEMCU=t85
11 15
 CC=/usr/bin/avr-gcc
12
-CFLAGS=-g -Os -Wall -mcall-prologues -mmcu=$(MCU)
16
+CFLAGS=-g -Os -Wall -mcall-prologues -mmcu=$(MCU) -DI2C_SLAVE_ADDRESS=$(I2C_ADDR)
13 17
 OBJ2HEX=/usr/bin/avr-objcopy
14 18
 AVRDUDE=avrdude
15 19
 

+ 266
- 253
control/tiny/i2c_timer_pwm.c Ver arquivo

@@ -1,10 +1,14 @@
1
+// w 60 0  1 10    : w i2c_addr SetPWM enable duty_val
2
+// w 60 5 12  8 32 : w i2c_addr write addrFl|src coarse_val
3
+// w 60 4  0  5    : w i2c_addr read  src read_addr  (set the read address to register 5)
4
+// r 60 4  3       : r i2c_addr <dum> cnt            (read the first 3 reg's beginning w/ 5)
1 5
 /*                                    
2 6
                                     AT TINY 85
3 7
                                      +--\/--+
4 8
                               RESET _| 1  8 |_ +5V
5
-             ~OC1B       HOLD  DDB3 _| 2  7 |_ SCL
9
+             ~OC1B       HOLD  DDB3 _| 2  7 |_ SCL         yellow 
6 10
               OC1B      ONSET  DDB4 _| 3  6 |_ DDB1 LED
7
-                                GND _| 4  5 |_ SDA
11
+                                GND _| 4  5 |_ SDA         orange
8 12
                                      +------+
9 13
         * = Serial and/or programming pins on Arduino as ISP
10 14
 */
@@ -12,6 +16,7 @@
12 16
 
13 17
 // This program acts as the device (slave) for the control program i2c/a2a/c_ctl
14 18
 #define F_CPU 8000000L
19
+
15 20
 #include <stdio.h>
16 21
 #include <avr/io.h>
17 22
 #include <util/delay.h>
@@ -19,50 +24,98 @@
19 24
 
20 25
 #include "usiTwiSlave.h"
21 26
 
27
+#define HOLD_DIR DDB3
28
+#define ATTK_DIR DDB4
29
+#define LED_DIR  DDB1
30
+
31
+#define HOLD_PIN PINB3
32
+#define ATTK_PIN PINB4
33
+#define LED_PIN  PINB1
22 34
 
23
-#define I2C_SLAVE_ADDRESS 0x8 // the 7-bit address (remember to change this when adapting this example)
35
+// Opcodes
36
+enum
37
+{ 
38
+ kSetPwm_Op         =  0,  // Set PWM registers  0 {<enable> {<duty> {<freq>}}}
39
+ kNoteOnVel_Op      =  1,  // Turn on note       1 {<vel>}
40
+ kNoteOnUsec_Op     =  2,  // Turn on note       2 {<coarse> {<fine> {<prescale>}}}
41
+ kNoteOff_Op        =  3,  // Turn off note      3
42
+ kRead_Op           =  4,  // Read a value       4 {<src>} {<addr>} }  src: 0=reg 1=table 2=eeprom
43
+ kWrite_Op          =  5,  // Set write          5 {<addrfl|src> {addr}  {<value0> ... {<valueN>}} 
44
+ kInvalid_Op        =  6   //                      addrFl:0x80  src: 4=reg 5=table 6=eeprom                       
45
+};
24 46
 
25 47
 
26 48
 enum
27 49
 {
28
- kTmr0_Prescale_idx =  0,  // Timer 0 clock divider: 1=1,2=8,3=64,4=256,5=1024
29
- kTmr0_Coarse_idx   =  1,  // 
30
- kTmr0_Fine_idx     =  2,  //
31
- kPWM0_Duty_idx     =  3,  //
32
- kPWM0_Freq_idx     =  4,  // 1-4 = clock divider=1=1,2=8,3=64,4=256,5=1024 
33
- kCS13_10_idx       =  5,  // Timer 1 Prescalar (CS13,CS12,CS11,CS10) from Table 12-5 pg 89 (0-15)  prescaler = pow(2,val-1), 0=stop,1=1,2=2,3=4,4=8,....14=8192,15=16384  pre_scaled_hz = clock_hz/value
34
- kTmr1_Coarse_idx   =  6,  // count of times timer0 count to 255 before OCR1C is set to Tmr0_Fine
35
- kTmr1_Fine_idx     =  7,  // OCR1C timer match value
36
- kPWM1_Duty_idx     =  8,  //
37
- kPWM1_Freq_idx     =  9,  // 
38
- kTable_Addr_idx    = 10,  // Next table address to read/write 
39
- kTable_Coarse_idx  = 11,  // Next table coarse value to read/write
40
- kTable_Fine_idx    = 12,  // Next table fine value to read/write
50
+ kReg_Rd_Addr_idx    =  0,  // Next Reg Address to read
51
+ kTable_Rd_Addr_idx  =  1,  // Next Table Address to read
52
+ kEE_Rd_Addr_idx     =  2,  // Next EEPROM address to read
53
+ kRead_Src_idx       =  3,  // kReg_Rd_Addr_idx=reg,  kTable_Rd_Addr_idx=table, kEE_Rd_Addr_idx=eeprom
54
+ 
55
+ kReg_Wr_Addr_idx    =  4,  // Next Reg Address to write
56
+ kTable_Wr_Addr_idx  =  5,  // Next Table Address to write
57
+ kEE_Wr_Addr_idx     =  6,  // Next EEPROM address to write
58
+ kWrite_Dst_idx      =  7,  // kReg_Wr_Addr_idx=reg,  kTable_Wr_Addr_idx=table, kEE_Wr_Addr_idx=eeprom
59
+ 
60
+ kTmr_Coarse_idx     =  8,  //  
61
+ kTmr_Fine_idx       =  9,  // 
62
+ kTmr_Prescale_idx   = 10,  // Timer 0 clock divider: 1=1,2=8,3=64,4=256,5=1024  Default: 8 (32us)
63
+ 
64
+ kPwm_Enable_idx     = 11,  // 
65
+ kPwm_Duty_idx       = 12,  // 
66
+ kPwm_Freq_idx       = 13,  //
67
+
68
+ kMode_idx          = 14, // 1=repeat 2=pwm
69
+ kState_idx          = 15, // 1=attk 2=hold
70
+ kError_Code_idx     = 16,  // Error Code
41 71
  kMax_idx
42 72
 };
43 73
 
74
+enum
75
+{
76
+ kTmr_Repeat_Fl= 1,
77
+ kTmr_Pwm_Fl   = 2,
78
+ kAttk_Fl      = 1,
79
+ kHold_Fl      = 2
80
+};
81
+
82
+// Flags:
83
+// 1=Repeat: 1=Timer and PWM are free running. This allows testing with LED's. 0=Timer triggers does not reset on time out. 
84
+// 2=PWM:  On timer timeout  1=PWM HOLD 0=Set HOLD 
44 85
 
45 86
 volatile uint8_t ctl_regs[] =
46 87
 {
47
-   4,    //  0 (1-5)    4=32us per tick
48
- 123,    //  1 (0-255)  Timer 0 Coarse Value 
49
-   8,    //  2 (0-255)  Timer 0 Fine Value
50
- 127,    //  3 (0-255) Duty cycle
51
-   4,    //  4 (1-4)   PWM Frequency (clock pre-scaler)   
52
-   9,    //  5  9=32 us period w/ 8Mhz clock (timer tick rate) 
53
- 123,    //  6 (0-255) Tmr1_Coarse count of times timer count to 255 before loading Tmr0_Minor for final count.
54
-   8,    //  7 (0-254) Tmr1_Fine OCR1C value on final phase before triggering timer
55
- 127,    //  8 (0-255) PWM1 Duty cycle
56
- 254,    //  9 (0-255) PWM1 Frequency  (123 hz)
57
-   0,    // 10 (0-127) Next table addr to read/write
58
-   0,    // 11 (0-255) Next table coarse value to write
59
-   0,    // 12 (0-255) Next table fine value to write
88
+   0,                //  0 (0-(kMax_idx-1)) Reg Read Addr   
89
+   0,                //  1 (0-255)          Table Read Addr
90
+   0,                //  2 (0-255)          EE Read Addr  
91
+   kReg_Rd_Addr_idx, //  3 (0-2)    Read source   
92
+   0,                //  4 (0-(kMax_idx-1)) Reg Write Addr   
93
+   0,                //  5 (0-255)          Table Write Addr
94
+   0,                //  6 (0-255)          EE Write Addr     
95
+   kReg_Wr_Addr_idx, //  7 (0-2)    Write source
96
+ 123,                //  8 (0-255)  Timer 0 Coarse Value 
97
+   8,                //  9 (0-255)  Timer 0 Fine Value
98
+   4,                // 10 (1-5)    4=32us per tick
99
+   1,                // 11 (0-1)    Pwm Enable Flag
100
+ 127,                // 12 (0-255)  Pwm Duty cycle
101
+ 254,                // 13 (0-255)  Pwm Frequency  (123 hz)
102
+   0,                // 14 mode flags  1=Repeat 2=PWM
103
+   0,                // 15 state flags 1=attk 2=hold
104
+   0,                // 16 (0-255)  Error bit field
60 105
 };
61 106
 
62 107
 #define tableN 256
63
-uint8_t table[ tableN ];
108
+uint8_t table[ tableN ]; // [ coarse_0,fine_0, coarse_1, fine_1, .... coarse_127,fine_127]
64 109
  
65 110
 
111
+enum
112
+{
113
+ kInvalid_Read_Src_ErrFl  = 0x01,
114
+ kInvalid_Write_Dst_ErrFl = 0x02
115
+};
116
+
117
+#define set_error( flag ) ctl_regs[ kError_Code_idx ] |= (flag)
118
+
66 119
 //------------------------------------------------------------------------------
67 120
 //------------------------------------------------------------------------------
68 121
 //------------------------------------------------------------------------------
@@ -113,7 +166,7 @@ uint8_t EEPROM_read(uint8_t ucAddress)
113 166
 // r 8 kTable_Coarse_idx -> 127
114 167
 // r 8 kTable_Fine_idx   ->  64
115 168
 
116
-
169
+/*
117 170
 #define eeprom_addr( addr ) (kMax_idx + (addr))
118 171
 
119 172
 void table_write_cur_value( void )
@@ -138,19 +191,7 @@ void table_load( void )
138 191
     table[tbl_addr+1] = EEPROM_read( eeprom_addr(tbl_addr+1) );
139 192
   }  
140 193
 }
141
-
142
-void restore_memory_from_eeprom( void )
143
-{
144
-  /*
145
-  uint8_t i;
146
-  for(i=0; i<kMax_idx; ++i)
147
-  {
148
-    ctl_regs[i] = EEPROM_read( eeprom_addr( i ) );
149
-  }
150
-  */
151
-  
152
-  table_load();
153
-}
194
+*/
154 195
 
155 196
 
156 197
 //------------------------------------------------------------------------------
@@ -163,11 +204,15 @@ void restore_memory_from_eeprom( void )
163 204
 volatile uint8_t tmr0_state        = 0;    // 0=disabled 1=coarse mode, 2=fine mode 
164 205
 volatile uint8_t tmr0_coarse_cur   = 0;
165 206
 
207
+#define set_attack()    do { ctl_regs[kState_idx] |= kAttk_Fl;  PORTB |= _BV(ATTK_PIN);            } while(0)
208
+#define clear_attack()  do { PORTB &= ~_BV(ATTK_PIN);           ctl_regs[kState_idx] &= ~kAttk_Fl; } while(0)
209
+
210
+
166 211
 // Use the current tmr0 ctl_reg[] values to set the timer to the starting state.
167 212
 void tmr0_reset()
168 213
 {
169 214
   // if a coarse count exists then go into coarse mode 
170
-  if( ctl_regs[kTmr0_Coarse_idx] > 0 )
215
+  if( ctl_regs[kTmr_Coarse_idx] > 0 )
171 216
   {
172 217
     tmr0_state = 1;
173 218
     OCR0A      = 0xff;
@@ -175,10 +220,14 @@ void tmr0_reset()
175 220
   else // otherwise go into fine mode
176 221
   {
177 222
     tmr0_state = 2;
178
-    OCR0A     = ctl_regs[kTmr0_Fine_idx];
223
+    OCR0A     = ctl_regs[kTmr_Fine_idx];
179 224
   }
180 225
   
181
-  tmr0_coarse_cur = 0;  
226
+  tmr0_coarse_cur = 0;
227
+
228
+  ctl_regs[kState_idx] |= kAttk_Fl;      // set the attack state
229
+  PORTB                |= _BV(ATTK_PIN); // set the attack pin 
230
+  TIMSK                |= _BV(OCIE0A);   // enable the timer interrupt
182 231
 }
183 232
 
184 233
 ISR(TIMER0_COMPA_vect)
@@ -191,18 +240,50 @@ ISR(TIMER0_COMPA_vect)
191 240
 
192 241
     case 1: 
193 242
       // coarse mode
194
-      if( ++tmr0_coarse_cur >= ctl_regs[kTmr0_Coarse_idx] )
243
+      if( ++tmr0_coarse_cur >= ctl_regs[kTmr_Coarse_idx] )
195 244
       {
196 245
         tmr0_state  = 2;
197
-        OCR0A     = ctl_regs[kTmr0_Fine_idx];        
246
+        OCR0A     = ctl_regs[kTmr_Fine_idx];        
198 247
       }
199 248
       break;
200 249
 
201 250
     case 2:
202 251
       // fine mode
203
-      PINB = _BV(PINB4);  // writes to PINB toggle the pins
204 252
 
205
-      tmr0_reset(); // restart the timer 
253
+      // If in repeat mode
254
+      if(ctl_regs[kMode_idx] & kTmr_Repeat_Fl)
255
+      {
256
+        uint8_t fl = ctl_regs[kState_idx] & kAttk_Fl;
257
+        
258
+        tmr0_reset();  // restart the timer
259
+        
260
+        // ATTK_PIN is always set after tmr0_reset() but we need to toggle in 'repeat' mode
261
+        if( fl )
262
+        {
263
+          clear_attack();
264
+        }
265
+
266
+        // In repeat mode we run the PWM output continuously
267
+        TIMSK  |= _BV(OCIE1B) + _BV(TOIE1); // Enable PWM interrupts
268
+
269
+      }
270
+      else  // not in repeat mode
271
+      {
272
+        clear_attack();
273
+        
274
+        if( ctl_regs[kMode_idx] & kTmr_Pwm_Fl)
275
+        {
276
+          TIMSK  |= _BV(OCIE1B) + _BV(TOIE1);    // PWM interupt Enable interrupts          
277
+        }
278
+        else
279
+        {
280
+          PORTB |= _BV(HOLD_PIN); // set the HOLD pin          
281
+        }
282
+
283
+        TIMSK &= ~_BV(OCIE0A);   // clear timer interrupt
284
+        
285
+      }
286
+      
206 287
       break;
207 288
   }
208 289
 }
@@ -212,144 +293,42 @@ void timer0_init()
212 293
 {
213 294
   TIMSK  &= ~_BV(OCIE0A);    // Disable interrupt TIMER1_OVF
214 295
   TCCR0A  |=  0x02;           // CTC mode
215
-  TCCR0B  |= ctl_regs[kTmr0_Prescale_idx]; // set the prescaler
296
+  TCCR0B  |= ctl_regs[kTmr_Prescale_idx]; // set the prescaler
216 297
 
217 298
   GTCCR  |= _BV(PSR0);      // Set the pre-scaler to the selected value
218 299
   
219
-  tmr0_reset();              // set the timers starting state
220
-  
221
-  TIMSK  |= _BV(OCIE0A);     // Enable interrupt TIMER1_OVF  
222
-
223
-}
300
+  //tmr0_reset();              // set the timers starting state
224 301
 
225 302
 
226
-//------------------------------------------------------------------------------
227
-//------------------------------------------------------------------------------
228
-//------------------------------------------------------------------------------
229
-//
230
-// PWM (Timer0)
231
-//
232
-
233
-void pwm0_update()
234
-{
235
-  OCR0B   = ctl_regs[kPWM0_Duty_idx];  // 50% duty cycle
236
-  TCCR0B |= ctl_regs[kPWM0_Freq_idx]; // PWM frequency pre-scaler
237
-}
238
-
239
-void pwm0_init()
240
-{
241
-  // WGM[1:0] = 3 (TOP=255)
242
-  // OCR0B = duty cycle (0-100%)
243
-  // COM0A[1:0] = 2 non-inverted
244
-  //
245
-
246
-  TCCR0A |=  0x20   + 3;    // 0x20=non-inverting 3=WGM bits Fast-PWM mode (0=Bot 255=Top)
247
-  TCCR0B |=  0x00   + 4;    //                    3=256 pre-scaler  122Hz=1Mghz/(v*256) where v=64
248
-  
249
-  GTCCR  |= _BV(PSR0);      // Set the pre-scaler to the selected value
250
-
251
-  pwm0_update();
252
-
253
-  
254
-  DDRB |= _BV(DDB1);    // set direction on 
255 303
 }
256 304
 
257 305
 
258
-
259 306
 //------------------------------------------------------------------------------
260 307
 //------------------------------------------------------------------------------
261 308
 //------------------------------------------------------------------------------
262 309
 //
263
-// Timer1
310
+// Pwm
264 311
 //
312
+// PWM is optimized to use pins OC1A ,~OC1A, OC1B, ~OC1B
313
+// but since these pins are not available this code uses
314
+// ISR's to redirect the output to PIN3
265 315
 
266
-volatile uint8_t tmr1_state        = 0;    
267
-volatile uint8_t tmr1_coarse_cur   = 0;
268
-static   uint8_t tmr1_init_fl      = 0;
269
-
270
-void tmr1_reset()
316
+void pwm1_update()
271 317
 {
272
-  if( ctl_regs[kTmr1_Coarse_idx] > 0 )
273
-  {
274
-    tmr1_state = 1;
275
-    OCR1C     = 254;
276
-  }
277
-  else
278
-  {
279
-    tmr1_state = 2;
280
-    OCR1C     = ctl_regs[kTmr1_Fine_idx];
281
-  }
282
-  
283
-  tmr1_coarse_cur = 0;  
318
+  OCR1B   = ctl_regs[kPwm_Duty_idx]; // control duty cycle
319
+  OCR1C   = ctl_regs[kPwm_Freq_idx]; // PWM frequency pre-scaler
284 320
 }
285 321
 
286
-ISR(TIMER1_OVF_vect)
287
-{
288
-  if( !tmr1_init_fl )
289
-  {
290
-    PORTB |= _BV(PINB3);  // set PWM pin
291
-  }
292
-  else
293
-  {
294
-    switch( tmr1_state )
295
-    {
296
-    
297
-      case 0:
298
-        // disabled
299
-        break;
300
-
301
-      case 1:
302
-        // coarse mode
303
-        if( ++tmr1_coarse_cur >= ctl_regs[kTmr1_Coarse_idx] )
304
-        {
305
-          tmr1_state  = 2;
306
-          OCR1C     = ctl_regs[kTmr1_Fine_idx];        
307
-        }
308
-        break;
309 322
 
310
-      case 2:
311
-        // fine mode
312
-        PINB = _BV(PINB4);  // writes to PINB toggle the pins
313 323
 
314
-        tmr1_reset();
315
-        break;
316
-    }
317
-  } 
318
-}
319
-
320
-void timer1_init()
321
-{
322
-  TIMSK  &= ~_BV(TOIE1);    // Disable interrupt TIMER1_OVF
323
-  OCR1A   = 255;            // Set to anything greater than OCR1C (the counter never gets here.)
324
-  TCCR1  |= _BV(CTC1);      // Reset TCNT1 to 0 when TCNT1==OCR1C 
325
-  TCCR1  |= _BV(PWM1A);     // Enable PWM A (to generate overflow interrupts)
326
-  TCCR1  |= ctl_regs[kCS13_10_idx] & 0x0f;  // 
327
-  GTCCR  |= _BV(PSR1);      // Set the pre-scaler to the selected value
328
-
329
-  tmr1_reset();
330
-  tmr1_init_fl = 1;
331
-  TIMSK  |= _BV(TOIE1);     // Enable interrupt TIMER1_OVF  
332
-}
333
-
334
-//------------------------------------------------------------------------------
335
-//------------------------------------------------------------------------------
336
-//------------------------------------------------------------------------------
337
-//
338
-// PWM1
339
-//
340
-// PWM is optimized to use pins OC1A ,~OC1A, OC1B, ~OC1B but this code
341
-// but since these pins are not available this code uses
342
-// ISR's to redirect the output to PIN3
343
-
344
-void pwm1_update()
324
+ISR(TIMER1_OVF_vect)
345 325
 {
346
-  OCR1B   = ctl_regs[kPWM1_Duty_idx]; // control duty cycle
347
-  OCR1C   = ctl_regs[kPWM1_Freq_idx]; // PWM frequency pre-scaler
326
+  PORTB |= _BV(HOLD_PIN);  // set PWM pin
348 327
 }
349 328
 
350 329
 ISR(TIMER1_COMPB_vect)
351 330
 {
352
-  PORTB &= ~(_BV(PINB3)); // clear PWM pin
331
+  PORTB &= ~(_BV(HOLD_PIN)); // clear PWM pin
353 332
 }
354 333
 
355 334
 
@@ -357,7 +336,7 @@ void pwm1_init()
357 336
 {
358 337
   TIMSK  &= ~(_BV(OCIE1B) + _BV(TOIE1));    // Disable interrupts
359 338
   
360
-  DDRB   |=  _BV(DDB3);  // setup PB3 as output  
339
+  DDRB   |=  _BV(HOLD_DIR);  // setup PB3 as output  
361 340
 
362 341
   // set on TCNT1 == 0     // happens when TCNT1 matches OCR1C
363 342
   // clr on OCR1B == TCNT  // happens when TCNT1 matches OCR1B
@@ -367,11 +346,6 @@ void pwm1_init()
367 346
   GTCCR  |= _BV(PSR1);     // Set the pre-scaler to the selected value
368 347
 
369 348
   pwm1_update();
370
-
371
-  TIMSK  |= _BV(OCIE1B) + _BV(TOIE1);    // Enable interrupts
372
-
373
-
374
-  
375 349
 }
376 350
 
377 351
 //------------------------------------------------------------------------------
@@ -389,37 +363,83 @@ const uint8_t    reg_size = sizeof(ctl_regs);
389 363
 // than one byte of data (with TinyWireS.send) to the send-buffer when
390 364
 // using this callback
391 365
 //
366
+
392 367
 void on_request()
393 368
 {
394 369
   uint8_t val = 0;
395 370
   
396
-  switch( reg_position )
371
+  switch( ctl_regs[ kRead_Src_idx ] )
397 372
   {
398
-    case kTable_Coarse_idx:
399
-      val = table[ ctl_regs[kTable_Addr_idx]*2 + 0 ];      
373
+    case kReg_Rd_Addr_idx:
374
+      val = ctl_regs[ ctl_regs[kReg_Rd_Addr_idx] ];
400 375
       break;
401 376
 
402
-    case kTable_Fine_idx:
403
-      val = table[ ctl_regs[kTable_Addr_idx]*2 + 1 ];
377
+    case kTable_Rd_Addr_idx:
378
+      val = table[ ctl_regs[kTable_Rd_Addr_idx] ];
379
+      break;
380
+
381
+    case kEE_Rd_Addr_idx:
382
+      val = EEPROM_read(ctl_regs[kEE_Rd_Addr_idx]);
404 383
       break;
405
-      
406
-    default:
407
-      // read and transmit the requestd position
408
-      val = ctl_regs[reg_position];
409 384
 
385
+    default:
386
+      set_error( kInvalid_Read_Src_ErrFl );
387
+      return;
410 388
   }
411 389
   
412 390
   usiTwiTransmitByte(val);
391
+
392
+  ctl_regs[ ctl_regs[ kRead_Src_idx ]  ] += 1;
393
+
394
+}
395
+
396
+
397
+void _write_op( uint8_t* stack, uint8_t stackN )
398
+{
399
+  uint8_t stack_idx = 0;
413 400
   
414
-  // Increment the reg position on each read, and loop back to zero
415
-  reg_position++;
416
-  if (reg_position >= reg_size)
401
+  if( stackN > 0 )
417 402
   {
418
-    reg_position = 0;
403
+    uint8_t src     = stack[0] & 0x07;
404
+    uint8_t addr_fl = stack[0] & 0x08;
405
+
406
+    // verify the source value
407
+    if( src < kReg_Wr_Addr_idx  || src > kEE_Wr_Addr_idx )
408
+    {
409
+      set_error( kInvalid_Write_Dst_ErrFl );
410
+      return;
411
+    }
412
+
413
+    // set the write source
414
+    stack_idx                  = 1;
415
+    ctl_regs[ kWrite_Dst_idx ] = src;
416
+
417
+    // if an address value was passed also ....
418
+    if( addr_fl && stackN > 1 )
419
+    {
420
+      stack_idx       = 2;
421
+      ctl_regs[ src ] = stack[1];
422
+    }
419 423
   }
420
-  
421
-}
422 424
 
425
+  //
426
+  for(; stack_idx<stackN; ++stack_idx)
427
+  {
428
+    uint8_t addr_idx = ctl_regs[ ctl_regs[kWrite_Dst_idx] ]++;
429
+    uint8_t val      = stack[ stack_idx ];
430
+    
431
+    switch( ctl_regs[ kWrite_Dst_idx ] )
432
+    {
433
+      case kReg_Wr_Addr_idx:   ctl_regs[ addr_idx ]           = val;  break;
434
+      case kTable_Wr_Addr_idx: table[ addr_idx ]              = val;  break;
435
+      case kEE_Wr_Addr_idx:    EEPROM_write( table[ addr_idx ], val); break;
436
+
437
+      default:
438
+        set_error( kInvalid_Write_Dst_ErrFl );
439
+        break;
440
+    }
441
+  }
442
+}
423 443
 
424 444
 //
425 445
 // The I2C data received -handler
@@ -432,87 +452,80 @@ void on_request()
432 452
 
433 453
 void on_receive( uint8_t byteN )
434 454
 {
435
-    if (byteN < 1)
436
-    {
437
-        // Sanity-check
438
-        return;
439
-    }
440
-    if (byteN > TWI_RX_BUFFER_SIZE)
441
-    {
442
-        // Also insane number
443
-        return;
444
-    }
455
+  PINB = _BV(LED_PIN);  // writes to PINB toggle the pins
456
+
457
+  const uint8_t stackN = 16;
458
+  uint8_t stack_idx = 0;
459
+  uint8_t stack[ stackN ];
460
+  uint8_t i;
461
+  
462
+  if (byteN < 1 || byteN > TWI_RX_BUFFER_SIZE)
463
+  {
464
+    // Sanity-check
465
+    return;
466
+  }
445 467
 
446
-    // get the register index to read/write
447
-    reg_position = usiTwiReceiveByte();
468
+  // get the register index to read/write
469
+  uint8_t op_id = usiTwiReceiveByte();
448 470
     
449
-    byteN--;
471
+  byteN--;
450 472
 
451
-    // If only one byte was received then this was a read request
452
-    // and the buffer pointer (reg_position) is now set to return the byte
453
-    // at this location on the subsequent call to on_request() ...
454
-    if (!byteN)
455
-    {
456
-      return;
473
+  // If only one byte was received then this was a read request
474
+  // and the buffer pointer (reg_position) is now set to return the byte
475
+  // at this location on the subsequent call to on_request() ...
476
+  if(byteN)
477
+  {
478
+    while( byteN-- )
479
+    {  
480
+      stack[stack_idx] = usiTwiReceiveByte();
481
+      ++stack_idx;
457 482
     }
483
+  }
484
+  
485
+  switch( op_id )
486
+  {
487
+    case kSetPwm_Op:
488
+      for(i=0; i<stack_idx; ++i)
489
+        ctl_regs[ kPwm_Enable_idx + i ] = stack[i];
490
+      pwm1_update();
491
+      break;
492
+      
493
+    case kNoteOnUsec_Op:
494
+      for(i=0; i<stack_idx; ++i)
495
+        ctl_regs[ kTmr_Coarse_idx + i ] = stack[i];
496
+      tmr0_reset();
497
+      break;
458 498
 
459
-    // ... otherwise this was a write request and the buffer
460
-    // pointer is now pointing to the first byte to write to
461
-    while(byteN--)
462
-    {
463
-      // write the value
464
-      ctl_regs[reg_position] = usiTwiReceiveByte();
465
-
466
-      // Set timer 1
467
-      if( kTmr0_Prescale_idx <= reg_position && reg_position <= kTmr0_Fine_idx )
468
-      { timer0_init(); }
469
-      else
470
-
471
-          
472
-        // Set PWM 0
473
-        if( kPWM0_Duty_idx <= reg_position && reg_position <= kPWM0_Freq_idx )
474
-        { pwm0_update(); }
475
-        else
476
-        
477
-          // Set timer 1
478
-          if( kCS13_10_idx <= reg_position && reg_position <= kTmr1_Fine_idx )
479
-          { timer1_init(); }
480
-          else
481
-
482
-            // Set PWM 1
483
-            if( kPWM1_Duty_idx <= reg_position && reg_position <= kPWM1_Freq_idx )
484
-            { pwm1_update(); }
485
-            else
486
-          
487
-
488
-              // Write table
489
-              if( reg_position == kTable_Fine_idx )
490
-              { table_write_cur_value(); }
491
-        
492
-      reg_position++;
493
-        
494
-      if (reg_position >= reg_size)
499
+    case kNoteOff_Op:
500
+      TIMSK  &= ~(_BV(OCIE1B) + _BV(TOIE1)); // PWM interupt disable interrupts          
501
+      PORTB  &= ~_BV(HOLD_PIN);              // clear the HOLD pin          
502
+      break;
503
+
504
+
505
+    case kRead_Op:
506
+      if( stack_idx > 0 )
495 507
       {
496
-        reg_position = 0;
508
+        ctl_regs[ kRead_Src_idx ] = stack[0];
509
+      
510
+        if( stack_idx > 1 )
511
+          ctl_regs[ ctl_regs[ kRead_Src_idx ] ] = stack[1];
497 512
       }
513
+      break;
498 514
 
499
-        
500
-    }
501
-
502
-  
515
+    case kWrite_Op:
516
+      _write_op( stack, stack_idx );
517
+      break;
518
+  }
503 519
 }
504 520
 
505 521
 
506
-
507 522
 int main(void)
508 523
 {
509 524
   cli();        // mask all interupts
510 525
 
511 526
 
512
-  restore_memory_from_eeprom();
513
-  
514
-  DDRB  |=   _BV(DDB4)  + _BV(DDB3)  + _BV(DDB1);  // setup PB4,PB3,PB1 as output  
515
-  PORTB &= ~(_BV(PINB4) + _BV(PINB3) + _BV(PINB1)); // clear output pins
527
+  DDRB  |=   _BV(ATTK_DIR)  + _BV(HOLD_DIR)  + _BV(LED_DIR);  // setup PB4,PB3,PB1 as output  
528
+  PORTB &= ~(_BV(ATTK_PIN)  + _BV(HOLD_PIN)  + _BV(LED_PIN)); // clear output pins
516 529
 
517 530
   
518 531
   timer0_init();
@@ -525,9 +538,9 @@ int main(void)
525 538
   
526 539
   sei();
527 540
 
528
-  PINB = _BV(PINB4);  // writes to PINB toggle the pins
541
+  PINB = _BV(LED_PIN);  // writes to PINB toggle the pins
529 542
   _delay_ms(1000);  
530
-  PINB = _BV(PINB4);  // writes to PINB toggle the pins
543
+  PINB = _BV(LED_PIN);  // writes to PINB toggle the pins
531 544
 
532 545
   
533 546
   while(1)

Carregando…
Cancelar
Salvar