Added table writing (not yet tested) and removed 'repeat-mode'.
This commit is contained in:
parent
f24aec16e6
commit
5ffd77da17
@ -12,7 +12,7 @@ class TinyOp(Enum):
|
|||||||
noteOffOp = 3
|
noteOffOp = 3
|
||||||
setReadAddr = 4
|
setReadAddr = 4
|
||||||
writeOp = 5
|
writeOp = 5
|
||||||
setModeOp = 6
|
writeTableOp = 6
|
||||||
invalidOp = 7
|
invalidOp = 7
|
||||||
|
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ class TinyRegAddr(Enum):
|
|||||||
kTmrPrescaleAddr = 10
|
kTmrPrescaleAddr = 10
|
||||||
kPwmDutyAddr = 11
|
kPwmDutyAddr = 11
|
||||||
kPwmFreqAddr = 12
|
kPwmFreqAddr = 12
|
||||||
kModeAddr = 13
|
kPwmDivAddr = 13
|
||||||
kStateAddr = 14
|
kStateAddr = 14
|
||||||
kErrorCodeAddr = 15
|
kErrorCodeAddr = 15
|
||||||
|
|
||||||
@ -155,9 +155,10 @@ class Picadae:
|
|||||||
self.keyMapD = { d['midi']:d for d in key_mapL }
|
self.keyMapD = { d['midi']:d for d in key_mapL }
|
||||||
self.i2c_base_addr = i2c_base_addr
|
self.i2c_base_addr = i2c_base_addr
|
||||||
self.prescaler_usec = prescaler_usec
|
self.prescaler_usec = prescaler_usec
|
||||||
|
self.log_level = 0
|
||||||
|
|
||||||
self.serialProc.start()
|
self.serialProc.start()
|
||||||
|
|
||||||
def close( self ):
|
def close( self ):
|
||||||
self.serialProc.quit()
|
self.serialProc.quit()
|
||||||
|
|
||||||
@ -179,7 +180,6 @@ class Picadae:
|
|||||||
def call_op( self, midi_pitch, op_code, argL ):
|
def call_op( self, midi_pitch, op_code, argL ):
|
||||||
return self.write( self._pitch_to_i2c_addr( midi_pitch ), op_code, argL )
|
return self.write( self._pitch_to_i2c_addr( midi_pitch ), op_code, argL )
|
||||||
|
|
||||||
|
|
||||||
def set_read_addr( self, i2c_addr, mem_id, addr ):
|
def set_read_addr( self, i2c_addr, mem_id, addr ):
|
||||||
return self. write(i2c_addr, TinyOp.setReadAddr.value,[ mem_id, addr ])
|
return self. write(i2c_addr, TinyOp.setReadAddr.value,[ mem_id, addr ])
|
||||||
|
|
||||||
@ -211,7 +211,7 @@ class Picadae:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def block_on_picadae_read( self, midi_pitch, mem_id, reg_addr, byteOutN, time_out_ms ):
|
def block_on_picadae_read( self, midi_pitch, mem_id, reg_addr, byteOutN, time_out_ms=250 ):
|
||||||
|
|
||||||
i2c_addr = self._pitch_to_i2c_addr( midi_pitch )
|
i2c_addr = self._pitch_to_i2c_addr( midi_pitch )
|
||||||
|
|
||||||
@ -251,34 +251,33 @@ class Picadae:
|
|||||||
|
|
||||||
def get_velocity_map( self, midi_pitch, midi_vel, time_out_ms=250 ):
|
def get_velocity_map( self, midi_pitch, midi_vel, time_out_ms=250 ):
|
||||||
byteOutN = 2
|
byteOutN = 2
|
||||||
return self.block_on_picadae_read( midi_pitch, TinyConst.kRdTableSrcId.value, midi_vel*2, byteOutN, time_out_ms )
|
return self.block_on_picadae_read( midi_pitch, TinyConst.kRdTableSrcId.value, midi_vel*2, byteOutN, time_out_ms )
|
||||||
|
|
||||||
def set_pwm_duty( self, midi_pitch, duty_cycle_pct ):
|
def set_pwm( self, midi_pitch, duty_cycle_pct ):
|
||||||
return self.call_op( midi_pitch, TinyOp.setPwmOp.value, [ int( duty_cycle_pct * 255.0 /100.0 )])
|
return self.call_op( midi_pitch, TinyOp.setPwmOp.value, [ int( duty_cycle_pct * 255.0 /100.0 )])
|
||||||
|
|
||||||
def get_pwm_duty( self, midi_pitch, time_out_ms=250 ):
|
def get_pwm( self, midi_pitch, time_out_ms=250 ):
|
||||||
return self.block_on_picadae_read_reg( midi_pitch, TinyRegAddr.kPwmDutyAddr.value, time_out_ms=time_out_ms )
|
return self.block_on_picadae_read_reg( midi_pitch, TinyRegAddr.kPwmDutyAddr.value, time_out_ms=time_out_ms )
|
||||||
|
|
||||||
def set_pwm_freq( self, midi_pitch, freq_div_id ):
|
|
||||||
# pwm frequency divider 1=1,2=8,3=64,4=256,5=1024
|
|
||||||
assert( 1 <= freq_div_id and freq_div_id <= 5 )
|
|
||||||
pass
|
|
||||||
|
|
||||||
def get_pwm_freq( self, midi_pitch, time_out_ms=250 ):
|
def get_pwm_freq( self, midi_pitch, time_out_ms=250 ):
|
||||||
return self.block_on_picadae_read_reg( midi_pitch, TinyRegAddr.kPwmFreqAddr.value, time_out_ms=time_out_ms )
|
return self.block_on_picadae_read_reg( midi_pitch, TinyRegAddr.kPwmFreqAddr.value, time_out_ms=time_out_ms )
|
||||||
|
|
||||||
def set_mode( self, midi_pitch, mode ):
|
def get_pwm_div( self, midi_pitch, time_out_ms=250 ):
|
||||||
# TODO validate mode value
|
return self.block_on_picadae_read_reg( midi_pitch, TinyRegAddr.kPwmDivAddr.value, time_out_ms=time_out_ms )
|
||||||
return self.call_op( midi_pitch, TinyOp.setModeOp.value, [ mode ] )
|
|
||||||
|
def write_table( self, midi_pitch, time_out_ms=250 ):
|
||||||
def get_mode( self, midi_pitch, time_out_ms=250 ):
|
# TODO: sending a dummy byte because we can't handle sending a command with no data bytes.
|
||||||
return self.block_on_picadae_read_reg( midi_pitch, TinyRegAddr.kModeAddr.value, time_out_ms=time_out_ms )
|
return self.call_op( midi_pitch, TinyOp.writeTableOp.value,[0])
|
||||||
|
|
||||||
def make_note( self, midi_pitch, atk_us, dur_ms ):
|
def make_note( self, midi_pitch, atk_us, dur_ms ):
|
||||||
# TODO: handle error on note_on_us()
|
# TODO: handle error on note_on_us()
|
||||||
self.note_on_us(midi_pitch, atk_us);
|
self.note_on_us(midi_pitch, atk_us);
|
||||||
time.sleep( dur_ms / 1000.0 )
|
time.sleep( dur_ms / 1000.0 )
|
||||||
return self.note_off(midi_pitch)
|
return self.note_off(midi_pitch)
|
||||||
|
|
||||||
|
def set_log_level( self, log_level ):
|
||||||
|
self.log_level = log_level
|
||||||
|
return Result()
|
||||||
|
|
||||||
def _pitch_to_i2c_addr( self, pitch ):
|
def _pitch_to_i2c_addr( self, pitch ):
|
||||||
return self.keyMapD[ pitch ]['index'] + self.i2c_base_addr
|
return self.keyMapD[ pitch ]['index'] + self.i2c_base_addr
|
||||||
@ -305,11 +304,12 @@ class Picadae:
|
|||||||
return self.serialProc.send(SerialMsgId.DATA_MSG, byteA )
|
return self.serialProc.send(SerialMsgId.DATA_MSG, byteA )
|
||||||
|
|
||||||
def _print( self, opcode, i2c_addr, reg_addr, byteL ):
|
def _print( self, opcode, i2c_addr, reg_addr, byteL ):
|
||||||
|
|
||||||
s = "{} {} {}".format( opcode, i2c_addr, reg_addr )
|
|
||||||
|
|
||||||
for x in byteL:
|
if self.log_level:
|
||||||
s += " {}".format(x)
|
s = "{} {} {}".format( opcode, i2c_addr, reg_addr )
|
||||||
|
|
||||||
|
for x in byteL:
|
||||||
|
s += " {}".format(x)
|
||||||
|
|
||||||
|
|
||||||
print(s)
|
print(s)
|
||||||
|
@ -7,77 +7,44 @@ class PicadaeShell:
|
|||||||
def __init__( self, cfg ):
|
def __init__( self, cfg ):
|
||||||
self.p = None
|
self.p = None
|
||||||
self.parseD = {
|
self.parseD = {
|
||||||
'q':{ "func":None, "varN":0, "help":"quit"},
|
'q':{ "func":None, "minN":0, "maxN":0, "help":"quit"},
|
||||||
'?':{ "func":"help", "varN":0, "help":"Print usage text."},
|
'?':{ "func":"_help", "minN":0, "maxN":0, "help":"Print usage text."},
|
||||||
'w':{ "func":"write", "varN":-1, "help":"write <i2c_addr> <reg_addr> <data0> ... <dataN>"},
|
'w':{ "func":"_write", "minN":-1, "maxN":-1,"help":"write <i2c_addr> <reg_addr> <data0> ... <dataN>"},
|
||||||
'r':{ "func":"read", "varN":3, "help":"read <i2c_addr> <reg_addr> <byteN>"},
|
'r':{ "func":"_read", "minN":4, "maxN":4, "help":"read <i2c_addr> <src> <reg_addr> <byteN>"},
|
||||||
'v':{ "func":"note_on_vel", "varN":2, "help":"note-on <pitch> <vel>"},
|
'v':{ "func":"note_on_vel", "minN":2, "maxN":2, "help":"note-on <pitch> <vel>"},
|
||||||
'u':{ "func":"note_on_us", "varN":2, "help":"note-on <pitch> <usec>"},
|
'u':{ "func":"note_on_us", "minN":2, "maxN":3, "help":"note-on <pitch> <usec> <prescale> (1=1, 2=8, 3=64,(4)=256 16us, 5=1024)"},
|
||||||
'o':{ "func":"note_off", "varN":1, "help":"note-off <pitch>"},
|
'o':{ "func":"note_off", "minN":1, "maxN":1, "help":"note-off <pitch>"},
|
||||||
'T':{ "func":"set_vel_map", "varN":3, "help":"table <pitch> <vel> <usec>"},
|
'T':{ "func":"set_vel_map", "minN":3, "maxN":3, "help":"table <pitch> <vel> <usec>"},
|
||||||
't':{ "func":"get_vel_map", "varN":2, "help":"table <pitch> <vel>"},
|
't':{ "func":"get_vel_map", "minN":2, "maxN":2, "help":"table <pitch> <vel>"},
|
||||||
'D':{ "func":"set_pwm_duty", "varN":2, "help":"duty <pitch> <percent>"},
|
'D':{ "func":"set_pwm", "minN":2, "maxN":4, "help":"duty <pitch> <percent> {<hz> {<div>}} div:2=2,3=4,4=8,5=16,6=32,7=64,8=128,9=256,(10)=512 32us, 11=1024,12=2048,13=4096,14=8192,15=16384" },
|
||||||
'd':{ "func":"get_pwm_duty", "varN":1, "help":"duty <pitch>"},
|
'd':{ "func":"get_pwm_duty", "minN":1, "maxN":1, "help":"duty <pitch>"},
|
||||||
'F':{ "func":"set_pwm_freq", "varN":2, "help":"freq <pitch> <hz>"},
|
'f':{ "func":"get_pwm_freq", "minN":1, "maxN":1, "help":"freq <pitch>"},
|
||||||
'f':{ "func":"get_pwm_freq", "varN":1, "help":"freq <pitch>"},
|
'i':{ "func":"get_pwm_div", "minN":1, "maxN":1, "help":"div <pitch>"},
|
||||||
'M':{ "func":"set_mode", "varN":2, "help":"set_mode <pitch> <mode-bits> (1=repeat 2=pwm)" },
|
'W':{ "func":"write_table", "minN":1, "maxN":1, "help":"write_table <pitch>"},
|
||||||
'm':{ "func":"get_mode", "varN":1, "help":"get_mode <pitch>"},
|
'N':{ "func":"make_note", "minN":3, "maxN":3, "help":"note <pitch> atkUs durMs"},
|
||||||
'N':{ "func":"make_note", "varN":3, "help":"note <pitch> atkUs durMs"},
|
'L':{ "func":"set_log_level","minN":1, "maxN":1, "help":"log <level> (0-1)."}
|
||||||
}
|
}
|
||||||
|
|
||||||
def _do_help( self, _ ):
|
def _help( self, _=None ):
|
||||||
for k,d in self.parseD.items():
|
for k,d in self.parseD.items():
|
||||||
s = "{} = {}".format( k, d['help'] )
|
s = "{} = {}".format( k, d['help'] )
|
||||||
print(s)
|
print(s)
|
||||||
return Result()
|
return Result()
|
||||||
|
|
||||||
def _do_write( self, argL ):
|
def _write( self, argL ):
|
||||||
return self.p.write(argL[0], argL[1], argL[2:])
|
return self.p.write(argL[0], argL[1], argL[2:])
|
||||||
|
|
||||||
def _do_read( self, argL ):
|
def _read( self, argL ):
|
||||||
return self.p.read(*argL)
|
return self.p.block_on_picadae_read(argL[0], argL[1], argL[2], argL[3])
|
||||||
|
|
||||||
def _do_note_on_vel( self, argL ):
|
|
||||||
return self.p.note_on_vel(*argL)
|
|
||||||
|
|
||||||
def _do_note_on_us( self, argL ):
|
|
||||||
return self.p.note_on_us(*argL)
|
|
||||||
|
|
||||||
def _do_note_off( self, argL ):
|
|
||||||
return self.p.note_off(*argL)
|
|
||||||
|
|
||||||
def _do_set_vel_map( self, argL ):
|
|
||||||
return self.p.set_velocity_map(*argL)
|
|
||||||
|
|
||||||
def _do_get_vel_map( self, argL ):
|
|
||||||
return self.p.get_velocity_map(*argL)
|
|
||||||
|
|
||||||
def _do_set_pwm_duty( self, argL ):
|
|
||||||
return self.p.set_pwm_duty(*argL)
|
|
||||||
|
|
||||||
def _do_get_pwm_duty( self, argL ):
|
|
||||||
return self.p.get_pwm_duty(*argL)
|
|
||||||
|
|
||||||
def _do_set_pwm_freq( self, argL ):
|
|
||||||
return self.p.set_pwm_freq(*argL)
|
|
||||||
|
|
||||||
def _do_get_pwm_freq( self, argL ):
|
|
||||||
return self.p.get_pwm_freq(*argL)
|
|
||||||
|
|
||||||
def _do_set_mode( self, argL ):
|
|
||||||
return self.p.set_mode(*argL)
|
|
||||||
|
|
||||||
def _do_get_mode( self, argL ):
|
|
||||||
return self.p.get_mode(*argL)
|
|
||||||
|
|
||||||
def _do_make_note( self, argL ):
|
|
||||||
return self.p.make_note(*argL)
|
|
||||||
|
|
||||||
def _syntaxError( self, msg ):
|
def _syntaxError( self, msg ):
|
||||||
print("Syntax Error: " + msg )
|
print("Syntax Error: " + msg )
|
||||||
return Result()
|
return Result()
|
||||||
|
|
||||||
def _exec_cmd( self, tokL ):
|
def _exec_cmd( self, tokL ):
|
||||||
|
|
||||||
|
result = Result()
|
||||||
|
|
||||||
if len(tokL) <= 0:
|
if len(tokL) <= 0:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -88,21 +55,29 @@ class PicadaeShell:
|
|||||||
|
|
||||||
d = self.parseD[ opcode ]
|
d = self.parseD[ opcode ]
|
||||||
|
|
||||||
func_name = "_do_" + d['func']
|
func_name = d['func']
|
||||||
|
func = None
|
||||||
|
|
||||||
|
# find the function associated with this command
|
||||||
if hasattr(self, func_name ):
|
if hasattr(self, func_name ):
|
||||||
func = getattr(self, func_name )
|
func = getattr(self, func_name )
|
||||||
|
elif hasattr(self.p, func_name ):
|
||||||
|
func = getattr(self.p, func_name )
|
||||||
|
else:
|
||||||
|
return self._syntaxError("Exec function not found: '{}'.".format(func_name))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
argL = [ int(tokL[i]) for i in range(1,len(tokL)) ]
|
# convert the parameter list into integers
|
||||||
except:
|
argL = [ int(tokL[i]) for i in range(1,len(tokL)) ]
|
||||||
return self._syntaxError("Unable to create integer arguments.")
|
except:
|
||||||
|
return self._syntaxError("Unable to create integer arguments.")
|
||||||
|
|
||||||
if d['varN'] != -1 and len(argL) != d['varN']:
|
# validate the count of command args
|
||||||
return self._syntaxError("Argument mismatch {} != {}.".format(len(argL),d['varN']))
|
if d['minN'] != -1 and (d['minN'] > len(argL) or len(argL) > d['maxN']):
|
||||||
|
return self._syntaxError("Argument count mismatch. {} is out of range:{} to {}".format(len(argL),d['minN'],d['maxN']))
|
||||||
result = func(argL)
|
|
||||||
|
# call the command function
|
||||||
|
result = func(*argL)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@ -35,13 +35,13 @@
|
|||||||
// Opcodes
|
// Opcodes
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
kSetPwm_Op = 0, // Set PWM registers 0 {<duty> {<freq>}}
|
kSetPwm_Op = 0, // Set PWM duty/hz/div 0 {<duty> {<freq> {<div>}}} div:2=2,3=4,4=8,5=16,6=32,7=64,8=128,9=256,10=512,11=1024,12=2048,13=4096,14=8192,15=16384
|
||||||
kNoteOnVel_Op = 1, // Turn on note 1 {<vel>}
|
kNoteOnVel_Op = 1, // Turn on note 3 {<vel>}
|
||||||
kNoteOnUsec_Op = 2, // Turn on note 2 {<coarse> {<fine> {<prescale>}}}
|
kNoteOnUsec_Op = 2, // Turn on note 4 {<coarse> {<fine> {<prescale>}}}
|
||||||
kNoteOff_Op = 3, // Turn off note 3
|
kNoteOff_Op = 3, // Turn off note 5
|
||||||
kSetReadAddr_Op = 4, // Set a read addr. 4 {<src>} {<addr>} } src: 0=reg 1=table 2=eeprom
|
kSetReadAddr_Op = 4, // Set a read addr. 6 {<src>} {<addr>} } src: 0=reg 1=table 2=eeprom
|
||||||
kWrite_Op = 5, // Set write 5 {<addrfl|src> {addr} {<value0> ... {<valueN>}} addrFl:0x80 src: 4=reg 5=table 6=eeprom
|
kWrite_Op = 5, // Set write 7 {<addrfl|src> {addr} {<value0> ... {<valueN>}} addrFl:0x80 src: 4=reg 5=table 6=eeprom
|
||||||
kSetMode_Op = 6, // Set the mode flags 6 {<mode>} 1=repeat 2=pwm
|
kWriteTable_Op = 6, // Write table to EEprom 9
|
||||||
kInvalid_Op = 7 //
|
kInvalid_Op = 7 //
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -60,33 +60,25 @@ enum
|
|||||||
|
|
||||||
kTmr_Coarse_idx = 8, //
|
kTmr_Coarse_idx = 8, //
|
||||||
kTmr_Fine_idx = 9, //
|
kTmr_Fine_idx = 9, //
|
||||||
kTmr_Prescale_idx = 10, // Timer 0 clock divider: 1=1,2=8,3=64,4=256,5=1024 Default: 8 (16us)
|
kTmr_Prescale_idx = 10, // Timer 0 clock divider: 1=1,2=8,3=64,4=256,5=1024 Default: 4 (16us)
|
||||||
|
|
||||||
kPwm_Duty_idx = 11, //
|
kPwm_Duty_idx = 11, //
|
||||||
kPwm_Freq_idx = 12, //
|
kPwm_Freq_idx = 12, //
|
||||||
|
kPwm_Div_idx = 13, //
|
||||||
|
|
||||||
kMode_idx = 13, // 1=repeat 2=pwm
|
|
||||||
kState_idx = 14, // 1=attk 2=hold
|
kState_idx = 14, // 1=attk 2=hold
|
||||||
kError_Code_idx = 15, // Error Code
|
kError_Code_idx = 15, // Error Code
|
||||||
|
kMax_Coarse_Tmr_idx = 16, // Max. allowable coarse timer value
|
||||||
kMax_idx
|
kMax_idx
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
kMode_Repeat_Fl = 1,
|
kState_Attk_Fl = 1,
|
||||||
kMode_Pwm_Fl = 2,
|
kState_Hold_Fl = 2
|
||||||
kAttk_Fl = 1,
|
|
||||||
kHold_Fl = 2
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#define isInRepeatMode() ctl_regs[ kMode_idx ] & kMode_Repeat_Fl
|
|
||||||
#define isInPwmMode() ctl_regs[ kMode_idx ] & kMode_Pwm_Fl
|
|
||||||
|
|
||||||
// Flags:
|
|
||||||
// 1=Repeat: 1=Timer and PWM are free running. This allows testing with LED's. 0=Timer triggers does not reset on time out.
|
|
||||||
// 2=PWM: On timer timeout 1=PWM HOLD 0=Set HOLD
|
|
||||||
|
|
||||||
volatile uint8_t ctl_regs[] =
|
volatile uint8_t ctl_regs[] =
|
||||||
{
|
{
|
||||||
0, // 0 (0-(kMax_idx-1)) Reg Read Addr
|
0, // 0 (0-(kMax_idx-1)) Reg Read Addr
|
||||||
@ -99,26 +91,39 @@ volatile uint8_t ctl_regs[] =
|
|||||||
0, // 6 (0-255) EE Write Addr
|
0, // 6 (0-255) EE Write Addr
|
||||||
kReg_Wr_Addr_idx, // 7 (0-2) Write source
|
kReg_Wr_Addr_idx, // 7 (0-2) Write source
|
||||||
|
|
||||||
245, // 8 (0-255) Timer 0 Coarse Value
|
5, // 8 (0-255) Timer 0 Coarse Value (20400 us)
|
||||||
25, // 9 (0-255) Timer 0 Fine Value
|
0, // 9 (0-255) Timer 0 Fine Value
|
||||||
4, // 10 (1-5) 4=16us per tick
|
4, // 10 (1-5) 4=16us per tick
|
||||||
|
|
||||||
127, // 11 (0-255) Pwm Duty cycle
|
127, // 11 (0-255) Pwm Duty cycle
|
||||||
254, // 12 (0-255) Pwm Frequency (123 Hz)
|
254, // 12 (0-255) Pwm Frequency (123 Hz)
|
||||||
|
10, // 13 (0-15) Pwm clock div
|
||||||
|
|
||||||
kMode_Repeat_Fl, // 13 mode flags 1=Repeat 2=PWM
|
0, // 14 state flags 1=attk 2=hold (read/only)
|
||||||
0, // 14 state flags 1=attk 2=hold
|
|
||||||
0, // 15 (0-255) Error bit field
|
0, // 15 (0-255) Error bit field
|
||||||
|
14, // 16 (0-255) Max allowable coarse timer count
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// These registers are saved to Eeprom
|
||||||
|
uint8_t eeprom_addr[] =
|
||||||
|
{
|
||||||
|
kTmr_Prescale_idx,
|
||||||
|
kPwm_Duty_idx,
|
||||||
|
kPwm_Freq_idx,
|
||||||
|
kPwm_Div_idx
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define tableN 256
|
#define tableN 256
|
||||||
uint8_t table[ tableN ]; // [ coarse_0,fine_0, coarse_1, fine_1, .... coarse_127,fine_127]
|
uint8_t table[ tableN ]; // [ coarse_0,fine_0, coarse_1, fine_1, .... coarse_127,fine_127]
|
||||||
|
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
kInvalid_Read_Src_ErrFl = 0x01,
|
kInvalid_Read_Src_ErrFl = 0x01,
|
||||||
kInvalid_Write_Dst_ErrFl = 0x02
|
kInvalid_Write_Dst_ErrFl = 0x02,
|
||||||
|
kInvalid_Coarse_Tmr_ErrFl = 0x04
|
||||||
};
|
};
|
||||||
|
|
||||||
#define set_error( flag ) ctl_regs[ kError_Code_idx ] |= (flag)
|
#define set_error( flag ) ctl_regs[ kError_Code_idx ] |= (flag)
|
||||||
@ -143,7 +148,6 @@ void EEPROM_write(uint8_t ucAddress, uint8_t ucData)
|
|||||||
EECR |= (1<<EEPE); // Start eeprom write by setting EEPE
|
EECR |= (1<<EEPE); // Start eeprom write by setting EEPE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint8_t EEPROM_read(uint8_t ucAddress)
|
uint8_t EEPROM_read(uint8_t ucAddress)
|
||||||
{
|
{
|
||||||
// Wait for completion of previous write
|
// Wait for completion of previous write
|
||||||
@ -155,50 +159,33 @@ uint8_t EEPROM_read(uint8_t ucAddress)
|
|||||||
return EEDR; // Return data from data register
|
return EEDR; // Return data from data register
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
void write_table()
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Read/Write table
|
|
||||||
//
|
|
||||||
|
|
||||||
// To write table value 42 to 127 (coarse) 64 (fine)
|
|
||||||
//
|
|
||||||
// w 8 kTable_Addr_idx 42
|
|
||||||
// w 8 kTable_Coarse_idx 127
|
|
||||||
// w 8 kTable_fine_idx 64
|
|
||||||
//
|
|
||||||
// TO read table value 42
|
|
||||||
// w 8 kTable_Addr_idx 42
|
|
||||||
// r 8 kTable_Coarse_idx -> 127
|
|
||||||
// r 8 kTable_Fine_idx -> 64
|
|
||||||
|
|
||||||
/*
|
|
||||||
#define eeprom_addr( addr ) (kMax_idx + (addr))
|
|
||||||
|
|
||||||
void table_write_cur_value( void )
|
|
||||||
{
|
{
|
||||||
uint8_t tbl_addr = ctl_regs[ kTable_Addr_idx ] * 2;
|
uint8_t i;
|
||||||
|
uint8_t regN = sizeof(eeprom_addr);
|
||||||
table[ tbl_addr+0 ] = ctl_regs[ kTable_Coarse_idx ];
|
|
||||||
table[ tbl_addr+1 ] = ctl_regs[ kTable_Fine_idx ];
|
|
||||||
|
|
||||||
EEPROM_write( eeprom_addr( tbl_addr+0 ), ctl_regs[ kTable_Coarse_idx ] );
|
// write the persistent registers
|
||||||
EEPROM_write( eeprom_addr( tbl_addr+1 ), ctl_regs[ kTable_Fine_idx ]);
|
for(i=0; i<regN; ++i)
|
||||||
|
EEPROM_write( i, ctl_regs[ eeprom_addr[i] ] );
|
||||||
|
|
||||||
|
// write the table
|
||||||
|
for(i=0; i<tableN; ++i)
|
||||||
|
EEPROM_write( regN+i, table[i] );
|
||||||
}
|
}
|
||||||
|
|
||||||
void table_load( void )
|
void load_table()
|
||||||
{
|
{
|
||||||
uint8_t i = 0;
|
uint8_t i;
|
||||||
|
uint8_t regN = sizeof(eeprom_addr);
|
||||||
|
|
||||||
for(; i<128; ++i)
|
// read the persistent registers
|
||||||
{
|
for(i=0; i<regN; ++i)
|
||||||
uint8_t tbl_addr = i*2;
|
ctl_regs[ eeprom_addr[i] ] = EEPROM_read(i);
|
||||||
table[tbl_addr+0] = EEPROM_read( eeprom_addr(tbl_addr+0) );
|
|
||||||
table[tbl_addr+1] = EEPROM_read( eeprom_addr(tbl_addr+1) );
|
// read the tabke
|
||||||
}
|
for(i=0; i<tableN; ++i)
|
||||||
|
table[i] = EEPROM_read(regN + i);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@ -208,16 +195,20 @@ void table_load( void )
|
|||||||
// Timer0
|
// Timer0
|
||||||
//
|
//
|
||||||
|
|
||||||
volatile uint8_t tmr0_state = 0; // 0=disabled 1=coarse mode, 2=fine mode
|
volatile uint8_t tmr0_state = 0; // current timer mode: 0=disabled 1=coarse mode, 2=fine mode
|
||||||
volatile uint8_t tmr0_coarse_cur = 0;
|
volatile uint8_t tmr0_coarse_cur = 0;
|
||||||
|
|
||||||
#define set_attack() do { ctl_regs[kState_idx] |= kAttk_Fl; PORTB |= _BV(ATTK_PIN); } while(0)
|
#define set_attack() do { ctl_regs[kState_idx] |= kState_Attk_Fl; PORTB |= _BV(ATTK_PIN); } while(0)
|
||||||
#define clear_attack() do { PORTB &= ~_BV(ATTK_PIN); ctl_regs[kState_idx] &= ~kAttk_Fl; } while(0)
|
#define clear_attack() do { PORTB &= ~_BV(ATTK_PIN); ctl_regs[kState_idx] &= ~kState_Attk_Fl; } while(0)
|
||||||
|
|
||||||
|
|
||||||
// Use the current tmr0 ctl_reg[] values to set the timer to the starting state.
|
// Use the current tmr0 ctl_reg[] values to set the timer to the starting state.
|
||||||
void tmr0_reset()
|
void tmr0_reset()
|
||||||
{
|
{
|
||||||
|
tmr0_coarse_cur = 0; // clear the coarse time counter
|
||||||
|
ctl_regs[kState_idx] |= kState_Attk_Fl; // set the attack state
|
||||||
|
PORTB |= _BV(ATTK_PIN); // set the attack pin
|
||||||
|
|
||||||
// if a coarse count exists then go into coarse mode
|
// if a coarse count exists then go into coarse mode
|
||||||
if( ctl_regs[kTmr_Coarse_idx] > 0 )
|
if( ctl_regs[kTmr_Coarse_idx] > 0 )
|
||||||
{
|
{
|
||||||
@ -230,11 +221,7 @@ void tmr0_reset()
|
|||||||
OCR0A = ctl_regs[kTmr_Fine_idx];
|
OCR0A = ctl_regs[kTmr_Fine_idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
tmr0_coarse_cur = 0;
|
TIMSK |= _BV(OCIE0A); // enable the timer interrupt
|
||||||
|
|
||||||
ctl_regs[kState_idx] |= kAttk_Fl; // set the attack state
|
|
||||||
PORTB |= _BV(ATTK_PIN); // set the attack pin
|
|
||||||
TIMSK |= _BV(OCIE0A); // enable the timer interrupt
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ISR(TIMER0_COMPA_vect)
|
ISR(TIMER0_COMPA_vect)
|
||||||
@ -242,7 +229,7 @@ ISR(TIMER0_COMPA_vect)
|
|||||||
switch( tmr0_state )
|
switch( tmr0_state )
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
// disabled
|
// timer is disabled
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
@ -257,39 +244,12 @@ ISR(TIMER0_COMPA_vect)
|
|||||||
case 2:
|
case 2:
|
||||||
// fine mode
|
// fine mode
|
||||||
|
|
||||||
// If in repeat mode
|
// This marks the end of a timer period
|
||||||
if(ctl_regs[kMode_idx] & kMode_Repeat_Fl)
|
|
||||||
{
|
|
||||||
uint8_t fl = ctl_regs[kState_idx] & kAttk_Fl;
|
|
||||||
|
|
||||||
tmr0_reset(); // restart the timer
|
|
||||||
|
|
||||||
// ATTK_PIN is always set after tmr0_reset() but we need to toggle in 'repeat' mode
|
|
||||||
if( fl )
|
|
||||||
{
|
|
||||||
clear_attack();
|
|
||||||
}
|
|
||||||
|
|
||||||
// In repeat mode we run the PWM output continuously
|
clear_attack();
|
||||||
TIMSK |= _BV(OCIE1B) + _BV(TOIE1); // Enable PWM interrupts
|
|
||||||
|
|
||||||
}
|
|
||||||
else // not in repeat mode
|
|
||||||
{
|
|
||||||
clear_attack();
|
|
||||||
|
|
||||||
if( ctl_regs[kMode_idx] & kMode_Pwm_Fl)
|
TIMSK |= _BV(OCIE1B) + _BV(TOIE1); // PWM interupt Enable interrupts
|
||||||
{
|
TIMSK &= ~_BV(OCIE0A); // clear timer interrupt
|
||||||
TIMSK |= _BV(OCIE1B) + _BV(TOIE1); // PWM interupt Enable interrupts
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PORTB |= _BV(HOLD_PIN); // set the HOLD pin
|
|
||||||
}
|
|
||||||
|
|
||||||
TIMSK &= ~_BV(OCIE0A); // clear timer interrupt
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -343,7 +303,7 @@ void pwm1_init()
|
|||||||
// set on TCNT1 == 0 // happens when TCNT1 matches OCR1C
|
// set on TCNT1 == 0 // happens when TCNT1 matches OCR1C
|
||||||
// clr on OCR1B == TCNT // happens when TCNT1 matches OCR1B
|
// clr on OCR1B == TCNT // happens when TCNT1 matches OCR1B
|
||||||
// // COM1B1=1 COM1B0=0 (enable output on ~OC1B)
|
// // COM1B1=1 COM1B0=0 (enable output on ~OC1B)
|
||||||
TCCR1 |= 10; // 32us period (512 divider) prescaler
|
TCCR1 |= ctl_regs[ kPwm_Div_idx]; // 32us period (512 divider) prescaler
|
||||||
GTCCR |= _BV(PWM1B); // Enable PWM B and disconnect output pins
|
GTCCR |= _BV(PWM1B); // Enable PWM B and disconnect output pins
|
||||||
GTCCR |= _BV(PSR1); // Set the pre-scaler to the selected value
|
GTCCR |= _BV(PSR1); // Set the pre-scaler to the selected value
|
||||||
|
|
||||||
@ -487,20 +447,38 @@ void on_receive( uint8_t byteN )
|
|||||||
switch( op_id )
|
switch( op_id )
|
||||||
{
|
{
|
||||||
case kSetPwm_Op:
|
case kSetPwm_Op:
|
||||||
for(i=0; i<stack_idx && i<2; ++i)
|
for(i=0; i<stack_idx && i<3; ++i)
|
||||||
ctl_regs[ kPwm_Duty_idx + i ] = stack[i];
|
ctl_regs[ kPwm_Duty_idx + i ] = stack[i];
|
||||||
|
|
||||||
|
// if the PWM prescaler was changed
|
||||||
|
if( i == 3 )
|
||||||
|
pwm1_init();
|
||||||
|
|
||||||
pwm1_update();
|
pwm1_update();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case kNoteOnUsec_Op:
|
case kNoteOnUsec_Op:
|
||||||
for(i=0; i<stack_idx && i<3; ++i)
|
for(i=0; i<stack_idx && i<3; ++i)
|
||||||
ctl_regs[ kTmr_Coarse_idx + i ] = stack[i];
|
ctl_regs[ kTmr_Coarse_idx + i ] = stack[i];
|
||||||
|
|
||||||
|
// validate the coarse error value
|
||||||
|
if( ctl_regs[ kTmr_Coarse_idx ] > ctl_regs[ kMax_Coarse_Tmr_idx ])
|
||||||
|
{
|
||||||
|
ctl_regs[ kTmr_Coarse_idx ] = ctl_regs[ kMax_Coarse_Tmr_idx ];
|
||||||
|
set_error( kInvalid_Coarse_Tmr_ErrFl );
|
||||||
|
}
|
||||||
|
// if a prescaler was included then the timer needs to be re-initialized
|
||||||
|
if( i == 3 )
|
||||||
|
tmr0_init();
|
||||||
|
|
||||||
tmr0_reset();
|
tmr0_reset();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kNoteOff_Op:
|
case kNoteOff_Op:
|
||||||
|
TIMSK &= ~_BV(OCIE0A); // clear timer interrupt (shouldn't be necessary)
|
||||||
TIMSK &= ~(_BV(OCIE1B) + _BV(TOIE1)); // PWM interupt disable interrupts
|
TIMSK &= ~(_BV(OCIE1B) + _BV(TOIE1)); // PWM interupt disable interrupts
|
||||||
PORTB &= ~_BV(HOLD_PIN); // clear the HOLD pin
|
PORTB &= ~_BV(HOLD_PIN); // clear the HOLD pin
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kSetReadAddr_Op:
|
case kSetReadAddr_Op:
|
||||||
@ -517,13 +495,8 @@ void on_receive( uint8_t byteN )
|
|||||||
_write_op( stack, stack_idx );
|
_write_op( stack, stack_idx );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kSetMode_Op:
|
case kWriteTable_Op:
|
||||||
if( stack_idx > 0)
|
write_table();
|
||||||
{
|
|
||||||
ctl_regs[ kMode_idx ] = stack[0];
|
|
||||||
tmr0_reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -550,9 +523,6 @@ int main(void)
|
|||||||
_delay_ms(1000);
|
_delay_ms(1000);
|
||||||
PINB = _BV(LED_PIN); // writes to PINB toggle the pins
|
PINB = _BV(LED_PIN); // writes to PINB toggle the pins
|
||||||
|
|
||||||
// if in repeat mode
|
|
||||||
if( ctl_regs[ kMode_idx ] & kMode_Repeat_Fl)
|
|
||||||
tmr0_reset();
|
|
||||||
|
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user