Added table writing (not yet tested) and removed 'repeat-mode'.

This commit is contained in:
kevin.larke 2019-08-19 21:27:25 -04:00
parent f24aec16e6
commit 5ffd77da17
3 changed files with 154 additions and 209 deletions

View File

@ -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,6 +155,7 @@ 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()
@ -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 )
@ -253,26 +253,21 @@ class Picadae:
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 get_mode( self, midi_pitch, time_out_ms=250 ): def write_table( self, midi_pitch, time_out_ms=250 ):
return self.block_on_picadae_read_reg( midi_pitch, TinyRegAddr.kModeAddr.value, time_out_ms=time_out_ms ) # TODO: sending a dummy byte because we can't handle sending a command with no data bytes.
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()
@ -280,6 +275,10 @@ class Picadae:
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
@ -306,6 +305,7 @@ class Picadae:
def _print( self, opcode, i2c_addr, reg_addr, byteL ): def _print( self, opcode, i2c_addr, reg_addr, byteL ):
if self.log_level:
s = "{} {} {}".format( opcode, i2c_addr, reg_addr ) s = "{} {} {}".format( opcode, i2c_addr, reg_addr )
for x in byteL: for x in byteL:

View File

@ -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:
# convert the parameter list into integers
argL = [ int(tokL[i]) for i in range(1,len(tokL)) ] argL = [ int(tokL[i]) for i in range(1,len(tokL)) ]
except: except:
return self._syntaxError("Unable to create integer arguments.") 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

View File

@ -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,18 +91,30 @@ 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]
@ -118,7 +122,8 @@ uint8_t table[ tableN ]; // [ coarse_0,fine_0, coarse_1, fine_1, .... coarse_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 ]; // write the persistent registers
table[ tbl_addr+1 ] = ctl_regs[ kTable_Fine_idx ]; for(i=0; i<regN; ++i)
EEPROM_write( i, ctl_regs[ eeprom_addr[i] ] );
EEPROM_write( eeprom_addr( tbl_addr+0 ), ctl_regs[ kTable_Coarse_idx ] ); // write the table
EEPROM_write( eeprom_addr( tbl_addr+1 ), ctl_regs[ kTable_Fine_idx ]); 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,10 +221,6 @@ void tmr0_reset()
OCR0A = ctl_regs[kTmr_Fine_idx]; OCR0A = ctl_regs[kTmr_Fine_idx];
} }
tmr0_coarse_cur = 0;
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 TIMSK |= _BV(OCIE0A); // enable the timer interrupt
} }
@ -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,40 +244,13 @@ 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
TIMSK |= _BV(OCIE1B) + _BV(TOIE1); // Enable PWM interrupts
}
else // not in repeat mode
{
clear_attack(); clear_attack();
if( ctl_regs[kMode_idx] & kMode_Pwm_Fl)
{
TIMSK |= _BV(OCIE1B) + _BV(TOIE1); // PWM interupt Enable interrupts TIMSK |= _BV(OCIE1B) + _BV(TOIE1); // PWM interupt Enable interrupts
}
else
{
PORTB |= _BV(HOLD_PIN); // set the HOLD pin
}
TIMSK &= ~_BV(OCIE0A); // clear timer interrupt 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,18 +447,36 @@ 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;
@ -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)
{ {