瀏覽代碼

Added earlier and extended versions of picadae/tiny/i2c_timer_pwn*.c in the folder picadae/tiny/versions

master
kevin.larke 4 年之前
父節點
當前提交
766dc5d6a6

+ 394
- 0
control/tiny/versions/i2c_timer_pwm_0.c 查看文件

@@ -0,0 +1,394 @@
1
+/*                                    
2
+                                    AT TINY 85
3
+                                     +--\/--+
4
+                              RESET _| 1  8 |_ +5V
5
+                         HOLD  DDB3 _| 2  7 |_ SCL
6
+                        ONSET  DDB4 _| 3  6 |_ DDB1 LED
7
+                                GND _| 4  5 |_ SDA
8
+                                     +------+
9
+        * = Serial and/or programming pins on Arduino as ISP
10
+*/
11
+
12
+
13
+// This program acts as the device (slave) for the control program i2c/a2a/c_ctl
14
+#define F_CPU 8000000L
15
+#include <stdio.h>
16
+#include <avr/io.h>
17
+#include <util/delay.h>
18
+#include <avr/interrupt.h>
19
+
20
+#include "usiTwiSlave.h"
21
+
22
+#define I2C_SLAVE_ADDRESS 0x8 // the 7-bit address (remember to change this when adapting this example)
23
+
24
+
25
+enum
26
+{
27
+ kCS13_10_idx     = 0,  // 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
28
+ kTmr0_Coarse_idx = 1,  // count of times timer0 count to 255 before OCR1C is set to Tmr0_Fine
29
+ kTmr0_Fine_idx   = 2,  // OCR1C timer match value
30
+ kPWM_Duty_idx    = 3,  //
31
+ kPWM_Freq_idx    = 4,  // 1-4 = clock divider=1=1,2=8,3=64,4=256,5=1024
32
+ kTable_Addr_idx  = 5,  // Next table address to write 
33
+ kTable_Coarse_idx= 6,  // Next table coarse value to write
34
+ kTable_Fine_idx  = 7,  // Next table fine value to write
35
+ kMax_idx
36
+};
37
+
38
+volatile uint8_t ctl_regs[] =
39
+{
40
+   9,    // 0  9=32 us period w/ 8Mhz clock (timer tick rate) 
41
+ 123,    // 1 (0-255) Tmr0_Coarse count of times timer count to 255 before loading Tmr0_Minor for final count.
42
+   8,    // 2 (0-254) Tmr0_Fine OCR1C value on final phase before triggering timer
43
+ 127,    // 3 (0-255) Duty cycle
44
+   4,    // 4 (1-4)   PWM Frequency (clock pre-scaler)
45
+   0,    // 7 (0-127) Next table addr to read/write
46
+   0,    // 5 (0-255) Next table coarse value to write
47
+   0,    // 6 (0-255) Next table fine value to write
48
+};
49
+
50
+#define tableN 256
51
+uint8_t table[ tableN ];
52
+ 
53
+
54
+//------------------------------------------------------------------------------
55
+//------------------------------------------------------------------------------
56
+//------------------------------------------------------------------------------
57
+//
58
+// EEPROM
59
+//
60
+
61
+void EEPROM_write(uint8_t ucAddress, uint8_t ucData)
62
+{
63
+  // Wait for completion of previous write 
64
+  while(EECR & (1<<EEPE))
65
+  {}
66
+    
67
+  EECR = (0<<EEPM1)|(0<<EEPM0); // Set Programming mode   
68
+  EEAR = ucAddress;             // Set up address and data registers 
69
+  EEDR = ucData;  
70
+  EECR |= (1<<EEMPE);           // Write logical one to EEMPE 
71
+  EECR |= (1<<EEPE);            // Start eeprom write by setting EEPE 
72
+}
73
+
74
+
75
+uint8_t EEPROM_read(uint8_t ucAddress)
76
+{
77
+  // Wait for completion of previous write 
78
+  while(EECR & (1<<EEPE))
79
+  {}
80
+    
81
+  EEAR = ucAddress;  // Set up address register 
82
+  EECR |= (1<<EERE); // Start eeprom read by writing EERE 
83
+  return EEDR;       // Return data from data register 
84
+}
85
+
86
+//------------------------------------------------------------------------------
87
+//------------------------------------------------------------------------------
88
+//------------------------------------------------------------------------------
89
+//
90
+// Read/Write table
91
+//
92
+
93
+#define eeprom_addr( addr ) (kMax_idx + (addr))
94
+
95
+void table_write( void )
96
+{
97
+  uint8_t addr = ctl_regs[ kTable_Addr_idx ] * 2;
98
+  
99
+  table[ addr+0 ] = ctl_regs[ kTable_Coarse_idx ];
100
+  table[ addr+1 ] = ctl_regs[ kTable_Fine_idx ];
101
+
102
+  EEPROM_write( eeprom_addr( addr+0 ), ctl_regs[ kTable_Coarse_idx ] );
103
+  EEPROM_write( eeprom_addr( addr+1 ), ctl_regs[ kTable_Fine_idx ]); 
104
+}
105
+
106
+void table_load( void )
107
+{
108
+  uint8_t i = 0;
109
+
110
+  for(; i<128; ++i)
111
+  {
112
+    uint8_t addr  = i*2;
113
+    table[addr+0] = EEPROM_read( eeprom_addr(addr) );
114
+    table[addr+1] = EEPROM_read( eeprom_addr(addr) );
115
+  }  
116
+}
117
+
118
+void restore_memory_from_eeprom( void )
119
+{
120
+  uint8_t i;
121
+  for(i=0; i<kMax_idx; ++i)
122
+  {
123
+    ctl_regs[i] = eeprom_read( eeprom_addr( i ) );
124
+  }
125
+      
126
+  table_load();
127
+}
128
+
129
+//------------------------------------------------------------------------------
130
+//------------------------------------------------------------------------------
131
+//------------------------------------------------------------------------------
132
+//
133
+// PWM (Timer0)
134
+//
135
+
136
+void pwm0_update()
137
+{
138
+  OCR0B   = ctl_regs[kPWM_Duty_idx];  // 50% duty cycle
139
+  TCCR0B |= ctl_regs[kPWM_Freq_idx]; // PWM frequency pre-scaler
140
+}
141
+
142
+void pwm0_init()
143
+{
144
+  // WGM[1:0] = 3 (TOP=255)
145
+  // OCR0B = duty cycle (0-100%)
146
+  // COM0A[1:0] = 2 non-inverted
147
+  //
148
+
149
+  TCCR0A |=  0x20   + 3;    // 0x20=non-inverting 3=WGM bits Fast-PWM mode (0=Bot 255=Top)
150
+  TCCR0B |=  0x00   + 4;    //                    3=256 pre-scaler  122Hz=1Mghz/(v*256) where v=64
151
+
152
+  pwm0_update();
153
+    
154
+  DDRB |= _BV(DDB1);    
155
+}
156
+
157
+
158
+//------------------------------------------------------------------------------
159
+//------------------------------------------------------------------------------
160
+//------------------------------------------------------------------------------
161
+//
162
+// Timer1
163
+//
164
+
165
+volatile uint8_t tmr_state        = 0;    
166
+volatile uint8_t tmr_coarse_cur   = 0;
167
+
168
+void tmr_reset()
169
+{
170
+  if( ctl_regs[kTmr0_Coarse_idx] > 0 )
171
+  {
172
+    tmr_state = 1;
173
+    OCR1C     = 254;
174
+  }
175
+  else
176
+  {
177
+    tmr_state = 2;
178
+    OCR1C     = ctl_regs[kTmr0_Fine_idx];
179
+  }
180
+  
181
+  tmr_coarse_cur = 0;  
182
+}
183
+
184
+ISR(TIMER1_OVF_vect)
185
+{
186
+  switch( tmr_state )
187
+  {
188
+    case 0:
189
+      break;
190
+      
191
+    case 1:
192
+      if( ++tmr_coarse_cur >= ctl_regs[kTmr0_Coarse_idx] )
193
+      {
194
+        tmr_state  = 2;
195
+        OCR1C     = ctl_regs[kTmr0_Fine_idx];        
196
+      }
197
+      break;
198
+      
199
+    case 2:
200
+      PINB = _BV(PINB4) + _BV(PINB1);  // writes to PINB toggle the pins
201
+
202
+      tmr_reset();
203
+      break;
204
+  }
205
+}
206
+
207
+void timer1_init()
208
+{
209
+  TIMSK  &= ~_BV(TOIE1);    // Disable interrupt TIMER1_OVF
210
+  OCR1A   = 255;            // Set to anything greater than OCR1C (the counter never gets here.)
211
+  TCCR1  |= _BV(CTC1);      // Reset TCNT1 to 0 when TCNT1==OCR1C 
212
+  TCCR1  |= _BV(PWM1A);     // Enable PWM A
213
+  TCCR1  |= ctl_regs[kCS13_10_idx] & 0x0f;  // 
214
+  GTCCR  |= _BV(PSR1);      // Set the pre-scaler to the selected value
215
+
216
+  tmr_reset();
217
+  
218
+  TIMSK  |= _BV(TOIE1);     // Enable interrupt TIMER1_OVF  
219
+}
220
+
221
+
222
+//------------------------------------------------------------------------------
223
+//------------------------------------------------------------------------------
224
+//------------------------------------------------------------------------------
225
+
226
+// Tracks the current register pointer position
227
+volatile uint8_t reg_position = 0;
228
+const uint8_t    reg_size = sizeof(ctl_regs);
229
+
230
+//
231
+// Read Request Handler
232
+//
233
+// This is called for each read request we receive, never put more
234
+// than one byte of data (with TinyWireS.send) to the send-buffer when
235
+// using this callback
236
+//
237
+void on_request()
238
+{
239
+  uint8_t val = 0;
240
+  
241
+  switch( reg_position )
242
+  {
243
+    case kTable_Coarse_idx:
244
+      val = table[ reg_position*2 + 0 ];      
245
+      break;
246
+
247
+    case kTable_Fine_idx:
248
+      val = table[ reg_position*2 + 1 ];
249
+      break;
250
+      
251
+    default:
252
+      // read and transmit the requestd position
253
+      val = ctl_regs[reg_position];
254
+
255
+  }
256
+  
257
+  usiTwiTransmitByte(val);
258
+  
259
+  // Increment the reg position on each read, and loop back to zero
260
+  reg_position++;
261
+  if (reg_position >= reg_size)
262
+  {
263
+    reg_position = 0;
264
+  }
265
+  
266
+}
267
+
268
+
269
+//
270
+// The I2C data received -handler
271
+//
272
+// This needs to complete before the next incoming transaction (start,
273
+// data, restart/stop) on the bus does so be quick, set flags for long
274
+// running tasks to be called from the mainloop instead of running
275
+// them directly,
276
+//
277
+
278
+void on_receive( uint8_t byteN )
279
+{
280
+    if (byteN < 1)
281
+    {
282
+        // Sanity-check
283
+        return;
284
+    }
285
+    if (byteN > TWI_RX_BUFFER_SIZE)
286
+    {
287
+        // Also insane number
288
+        return;
289
+    }
290
+
291
+    // get the register index to read/write
292
+    reg_position = usiTwiReceiveByte();
293
+    
294
+    byteN--;
295
+
296
+    // If only one byte was received then this was a read request
297
+    // and the buffer pointer (reg_position) is now set to return the byte
298
+    // at this location on the subsequent call to on_request() ...
299
+    if (!byteN)
300
+    {
301
+      return;
302
+    }
303
+
304
+    // ... otherwise this was a write request and the buffer
305
+    // pointer is now pointing to the first byte to write to
306
+    while(byteN--)
307
+    {
308
+        ctl_regs[reg_position] = usiTwiReceiveByte();
309
+
310
+        // Set timer  
311
+        if( kCS13_10_idx <= reg_position && reg_position <= kTmr0_Fine_idx )
312
+        { timer1_init(); }
313
+        else
314
+
315
+        // Set PWM
316
+        if( kPWM_Duty_idx <= reg_position && reg_position <= kPWM_Freq_idx )
317
+        { pwm0_update(); }
318
+        else
319
+
320
+        // Write table
321
+        if( reg_position == kTable_Fine_idx )
322
+        { table_write(); }
323
+        
324
+        reg_position++;
325
+        
326
+        if (reg_position >= reg_size)
327
+        {
328
+            reg_position = 0;
329
+        }
330
+
331
+        
332
+    }
333
+
334
+  
335
+}
336
+
337
+
338
+
339
+int main(void)
340
+{
341
+  cli();        // mask all interupts
342
+    
343
+  DDRB  |= _BV(DDB4) + _BV(DDB1);  // setup PB4 as output
344
+  PORTB &= ~(_BV(PINB4) + _BV(PINB1));
345
+
346
+  timer1_init();
347
+  pwm0_init();
348
+  
349
+  // setup i2c library
350
+  usi_onReceiverPtr = on_receive; //on_receive;
351
+  usi_onRequestPtr  = on_request;
352
+  usiTwiSlaveInit(I2C_SLAVE_ADDRESS);
353
+  
354
+  sei();
355
+
356
+  PINB = _BV(PINB4);  // writes to PINB toggle the pins
357
+  _delay_ms(1000);  
358
+  PINB = _BV(PINB4);  // writes to PINB toggle the pins
359
+
360
+  
361
+  while(1)
362
+  {
363
+    //_delay_ms(1000);
364
+
365
+    if (!usi_onReceiverPtr)
366
+    {
367
+        // no onReceive callback, nothing to do...
368
+      continue;
369
+    }
370
+    
371
+    if (!(USISR & ( 1 << USIPF )))
372
+    {
373
+        // Stop not detected
374
+      continue;
375
+    }
376
+
377
+    
378
+    uint8_t amount = usiTwiAmountDataInReceiveBuffer();
379
+    if (amount == 0)
380
+    {
381
+        // no data in buffer
382
+      continue;
383
+    }
384
+
385
+    
386
+    usi_onReceiverPtr(amount);
387
+
388
+    
389
+  }
390
+  return 0;
391
+}
392
+
393
+
394
+

+ 566
- 0
control/tiny/versions/i2c_timer_pwm_1.c 查看文件

@@ -0,0 +1,566 @@
1
+/*                                    
2
+                                    AT TINY 85
3
+                                     +--\/--+
4
+                              RESET _| 1  8 |_ +5V
5
+             ~OC1B       HOLD  DDB3 _| 2  7 |_ SCL
6
+              OC1B      ONSET  DDB4 _| 3  6 |_ DDB1 LED
7
+                                GND _| 4  5 |_ SDA
8
+                                     +------+
9
+        * = Serial and/or programming pins on Arduino as ISP
10
+*/
11
+
12
+
13
+// This program acts as the device (slave) for the control program i2c/a2a/c_ctl
14
+#define F_CPU 8000000L
15
+#include <stdio.h>
16
+#include <avr/io.h>
17
+#include <util/delay.h>
18
+#include <avr/interrupt.h>
19
+
20
+#include "usiTwiSlave.h"
21
+
22
+
23
+#define I2C_SLAVE_ADDRESS 0x8 // the 7-bit address (remember to change this when adapting this example)
24
+
25
+
26
+enum
27
+{
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
41
+ kMax_idx
42
+};
43
+
44
+
45
+volatile uint8_t ctl_regs[] =
46
+{
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
60
+};
61
+
62
+#define tableN 256
63
+uint8_t table[ tableN ];
64
+ 
65
+
66
+//------------------------------------------------------------------------------
67
+//------------------------------------------------------------------------------
68
+//------------------------------------------------------------------------------
69
+//
70
+// EEPROM
71
+//
72
+
73
+void EEPROM_write(uint8_t ucAddress, uint8_t ucData)
74
+{
75
+  // Wait for completion of previous write 
76
+  while(EECR & (1<<EEPE))
77
+  {}
78
+    
79
+  EECR = (0<<EEPM1)|(0<<EEPM0); // Set Programming mode   
80
+  EEAR = ucAddress;             // Set up address and data registers 
81
+  EEDR = ucData;  
82
+  EECR |= (1<<EEMPE);           // Write logical one to EEMPE 
83
+  EECR |= (1<<EEPE);            // Start eeprom write by setting EEPE 
84
+}
85
+
86
+
87
+uint8_t EEPROM_read(uint8_t ucAddress)
88
+{
89
+  // Wait for completion of previous write 
90
+  while(EECR & (1<<EEPE))
91
+  {}
92
+    
93
+  EEAR = ucAddress;  // Set up address register 
94
+  EECR |= (1<<EERE); // Start eeprom read by writing EERE 
95
+  return EEDR;       // Return data from data register 
96
+}
97
+
98
+//------------------------------------------------------------------------------
99
+//------------------------------------------------------------------------------
100
+//------------------------------------------------------------------------------
101
+//
102
+// Read/Write table
103
+//
104
+
105
+// To write table value 42 to 127 (coarse) 64 (fine)
106
+//
107
+// w 8 kTable_Addr_idx 42
108
+// w 8 kTable_Coarse_idx 127
109
+// w 8 kTable_fine_idx 64
110
+//
111
+// TO read table value 42
112
+// w 8 kTable_Addr_idx 42
113
+// r 8 kTable_Coarse_idx -> 127
114
+// r 8 kTable_Fine_idx   ->  64
115
+
116
+
117
+#define eeprom_addr( addr ) (kMax_idx + (addr))
118
+
119
+void table_write_cur_value( void )
120
+{
121
+  uint8_t tbl_addr = ctl_regs[ kTable_Addr_idx ] * 2;
122
+  
123
+  table[ tbl_addr+0 ] = ctl_regs[ kTable_Coarse_idx ];
124
+  table[ tbl_addr+1 ] = ctl_regs[ kTable_Fine_idx ];
125
+
126
+  EEPROM_write( eeprom_addr( tbl_addr+0 ), ctl_regs[ kTable_Coarse_idx ] );
127
+  EEPROM_write( eeprom_addr( tbl_addr+1 ), ctl_regs[ kTable_Fine_idx ]); 
128
+}
129
+
130
+void table_load( void )
131
+{
132
+  uint8_t i = 0;
133
+
134
+  for(; i<128; ++i)
135
+  {
136
+    uint8_t tbl_addr  = i*2;
137
+    table[tbl_addr+0] = EEPROM_read( eeprom_addr(tbl_addr+0) );
138
+    table[tbl_addr+1] = EEPROM_read( eeprom_addr(tbl_addr+1) );
139
+  }  
140
+}
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
+}
154
+
155
+
156
+//------------------------------------------------------------------------------
157
+//------------------------------------------------------------------------------
158
+//------------------------------------------------------------------------------
159
+//
160
+// Timer0
161
+//
162
+
163
+volatile uint8_t tmr0_state        = 0;    // 0=disabled 1=coarse mode, 2=fine mode 
164
+volatile uint8_t tmr0_coarse_cur   = 0;
165
+
166
+// Use the current tmr0 ctl_reg[] values to set the timer to the starting state.
167
+void tmr0_reset()
168
+{
169
+  // if a coarse count exists then go into coarse mode 
170
+  if( ctl_regs[kTmr0_Coarse_idx] > 0 )
171
+  {
172
+    tmr0_state = 1;
173
+    OCR0A      = 0xff;
174
+  }
175
+  else // otherwise go into fine mode
176
+  {
177
+    tmr0_state = 2;
178
+    OCR0A     = ctl_regs[kTmr0_Fine_idx];
179
+  }
180
+  
181
+  tmr0_coarse_cur = 0;  
182
+}
183
+
184
+ISR(TIMER0_COMPA_vect)
185
+{
186
+  switch( tmr0_state )
187
+  {
188
+    case 0:
189
+      // disabled
190
+      break;
191
+
192
+    case 1: 
193
+      // coarse mode
194
+      if( ++tmr0_coarse_cur >= ctl_regs[kTmr0_Coarse_idx] )
195
+      {
196
+        tmr0_state  = 2;
197
+        OCR0A     = ctl_regs[kTmr0_Fine_idx];        
198
+      }
199
+      break;
200
+
201
+    case 2:
202
+      // fine mode
203
+      PINB = _BV(PINB4);  // writes to PINB toggle the pins
204
+
205
+      tmr0_reset(); // restart the timer 
206
+      break;
207
+  }
208
+}
209
+
210
+
211
+void timer0_init()
212
+{
213
+  TIMSK  &= ~_BV(OCIE0A);    // Disable interrupt TIMER1_OVF
214
+  TCCR0A  |=  0x02;           // CTC mode
215
+  TCCR0B  |= ctl_regs[kTmr0_Prescale_idx]; // set the prescaler
216
+
217
+  GTCCR  |= _BV(PSR0);      // Set the pre-scaler to the selected value
218
+  
219
+  tmr0_reset();              // set the timers starting state
220
+  
221
+  TIMSK  |= _BV(OCIE0A);     // Enable interrupt TIMER1_OVF  
222
+
223
+}
224
+
225
+
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
+}
256
+
257
+
258
+
259
+//------------------------------------------------------------------------------
260
+//------------------------------------------------------------------------------
261
+//------------------------------------------------------------------------------
262
+//
263
+// Timer1
264
+//
265
+
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()
271
+{
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;  
284
+}
285
+
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
+
310
+      case 2:
311
+        // fine mode
312
+        PINB = _BV(PINB4);  // writes to PINB toggle the pins
313
+
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()
345
+{
346
+  OCR1B   = ctl_regs[kPWM1_Duty_idx]; // control duty cycle
347
+  OCR1C   = ctl_regs[kPWM1_Freq_idx]; // PWM frequency pre-scaler
348
+}
349
+
350
+ISR(TIMER1_COMPB_vect)
351
+{
352
+  PORTB &= ~(_BV(PINB3)); // clear PWM pin
353
+}
354
+
355
+
356
+void pwm1_init()
357
+{
358
+  TIMSK  &= ~(_BV(OCIE1B) + _BV(TOIE1));    // Disable interrupts
359
+  
360
+  DDRB   |=  _BV(DDB3);  // setup PB3 as output  
361
+
362
+  // set on TCNT1 == 0     // happens when TCNT1 matches OCR1C
363
+  // clr on OCR1B == TCNT  // happens when TCNT1 matches OCR1B
364
+  //                       // COM1B1=1 COM1B0=0 (enable output on ~OC1B)
365
+  TCCR1  |= 9;             // 32us period (256 divider) prescaler
366
+  GTCCR  |= _BV(PWM1B);    // Enable PWM B and disconnect output pins
367
+  GTCCR  |= _BV(PSR1);     // Set the pre-scaler to the selected value
368
+
369
+  pwm1_update();
370
+
371
+  TIMSK  |= _BV(OCIE1B) + _BV(TOIE1);    // Enable interrupts
372
+
373
+
374
+  
375
+}
376
+
377
+//------------------------------------------------------------------------------
378
+//------------------------------------------------------------------------------
379
+//------------------------------------------------------------------------------
380
+
381
+// Tracks the current register pointer position
382
+volatile uint8_t reg_position = 0;
383
+const uint8_t    reg_size = sizeof(ctl_regs);
384
+
385
+//
386
+// Read Request Handler
387
+//
388
+// This is called for each read request we receive, never put more
389
+// than one byte of data (with TinyWireS.send) to the send-buffer when
390
+// using this callback
391
+//
392
+void on_request()
393
+{
394
+  uint8_t val = 0;
395
+  
396
+  switch( reg_position )
397
+  {
398
+    case kTable_Coarse_idx:
399
+      val = table[ ctl_regs[kTable_Addr_idx]*2 + 0 ];      
400
+      break;
401
+
402
+    case kTable_Fine_idx:
403
+      val = table[ ctl_regs[kTable_Addr_idx]*2 + 1 ];
404
+      break;
405
+      
406
+    default:
407
+      // read and transmit the requestd position
408
+      val = ctl_regs[reg_position];
409
+
410
+  }
411
+  
412
+  usiTwiTransmitByte(val);
413
+  
414
+  // Increment the reg position on each read, and loop back to zero
415
+  reg_position++;
416
+  if (reg_position >= reg_size)
417
+  {
418
+    reg_position = 0;
419
+  }
420
+  
421
+}
422
+
423
+
424
+//
425
+// The I2C data received -handler
426
+//
427
+// This needs to complete before the next incoming transaction (start,
428
+// data, restart/stop) on the bus does so be quick, set flags for long
429
+// running tasks to be called from the mainloop instead of running
430
+// them directly,
431
+//
432
+
433
+void on_receive( uint8_t byteN )
434
+{
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
+    }
445
+
446
+    // get the register index to read/write
447
+    reg_position = usiTwiReceiveByte();
448
+    
449
+    byteN--;
450
+
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;
457
+    }
458
+
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)
495
+      {
496
+        reg_position = 0;
497
+      }
498
+
499
+        
500
+    }
501
+
502
+  
503
+}
504
+
505
+
506
+
507
+int main(void)
508
+{
509
+  cli();        // mask all interupts
510
+
511
+
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
516
+
517
+  
518
+  timer0_init();
519
+  pwm1_init();
520
+  
521
+  // setup i2c library
522
+  usi_onReceiverPtr = on_receive; 
523
+  usi_onRequestPtr  = on_request;
524
+  usiTwiSlaveInit(I2C_SLAVE_ADDRESS);
525
+  
526
+  sei();
527
+
528
+  PINB = _BV(PINB4);  // writes to PINB toggle the pins
529
+  _delay_ms(1000);  
530
+  PINB = _BV(PINB4);  // writes to PINB toggle the pins
531
+
532
+  
533
+  while(1)
534
+  {
535
+    //_delay_ms(1000);
536
+
537
+    if (!usi_onReceiverPtr)
538
+    {
539
+        // no onReceive callback, nothing to do...
540
+      continue;
541
+    }
542
+    
543
+    if (!(USISR & ( 1 << USIPF )))
544
+    {
545
+        // Stop not detected
546
+      continue;
547
+    }
548
+
549
+    
550
+    uint8_t amount = usiTwiAmountDataInReceiveBuffer();
551
+    if (amount == 0)
552
+    {
553
+        // no data in buffer
554
+      continue;
555
+    }
556
+
557
+    
558
+    usi_onReceiverPtr(amount);
559
+
560
+    
561
+  }
562
+  return 0;
563
+}
564
+
565
+
566
+

+ 444
- 0
control/tiny/versions/i2c_timer_pwm_1a.c 查看文件

@@ -0,0 +1,444 @@
1
+/*                                    
2
+                                    AT TINY 85
3
+                                     +--\/--+
4
+                              RESET _| 1  8 |_ +5V
5
+             ~OC1B       HOLD  DDB3 _| 2  7 |_ SCL
6
+              OC1B      ONSET  DDB4 _| 3  6 |_ DDB1 LED
7
+                                GND _| 4  5 |_ SDA
8
+                                     +------+
9
+        * = Serial and/or programming pins on Arduino as ISP
10
+*/
11
+
12
+
13
+// This program acts as the device (slave) for the control program i2c/a2a/c_ctl
14
+#define F_CPU 8000000L
15
+#include <stdio.h>
16
+#include <avr/io.h>
17
+#include <util/delay.h>
18
+#include <avr/interrupt.h>
19
+
20
+#include "usiTwiSlave.h"
21
+
22
+
23
+enum
24
+{
25
+ kTmr0_Prescale_idx =  0,  // Timer 0 clock divider: 1=1,2=8,3=64,4=256,5=1024
26
+ kTmr0_Coarse_idx   =  1,  // 
27
+ kTmr0_Fine_idx     =  2,  //
28
+ kPWM1_Duty_idx     =  3,  //
29
+ kPWM1_Freq_idx     =  4,  // 
30
+ kTable_Addr_idx    =  5,  // Next table address to read/write 
31
+ kTable_Coarse_idx  =  6,  // Next table coarse value to read/write
32
+ kTable_Fine_idx    =  7,  // Next table fine value to read/write
33
+ kMax_idx
34
+};
35
+
36
+
37
+volatile uint8_t ctl_regs[] =
38
+{
39
+   4,    //  0 (1-5)    4=32us per tick
40
+ 123,    //  1 (0-255)  Timer 0 Coarse Value 
41
+   8,    //  2 (0-255)  Timer 0 Fine Value
42
+ 127,    //  3 (0-255) PWM1 Duty cycle
43
+ 254,    //  4 (0-255) PWM1 Frequency  (123 hz)
44
+   0,    //  5 (0-127) Next table addr to read/write
45
+   0,    //  6 (0-255) Next table coarse value to write
46
+   0,    //  7 (0-255) Next table fine value to write
47
+};
48
+
49
+#define tableN 256
50
+uint8_t table[ tableN ];
51
+ 
52
+
53
+//------------------------------------------------------------------------------
54
+//------------------------------------------------------------------------------
55
+//------------------------------------------------------------------------------
56
+//
57
+// EEPROM
58
+//
59
+
60
+void EEPROM_write(uint8_t ucAddress, uint8_t ucData)
61
+{
62
+  // Wait for completion of previous write 
63
+  while(EECR & (1<<EEPE))
64
+  {}
65
+    
66
+  EECR = (0<<EEPM1)|(0<<EEPM0); // Set Programming mode   
67
+  EEAR = ucAddress;             // Set up address and data registers 
68
+  EEDR = ucData;  
69
+  EECR |= (1<<EEMPE);           // Write logical one to EEMPE 
70
+  EECR |= (1<<EEPE);            // Start eeprom write by setting EEPE 
71
+}
72
+
73
+
74
+uint8_t EEPROM_read(uint8_t ucAddress)
75
+{
76
+  // Wait for completion of previous write 
77
+  while(EECR & (1<<EEPE))
78
+  {}
79
+    
80
+  EEAR = ucAddress;  // Set up address register 
81
+  EECR |= (1<<EERE); // Start eeprom read by writing EERE 
82
+  return EEDR;       // Return data from data register 
83
+}
84
+
85
+//------------------------------------------------------------------------------
86
+//------------------------------------------------------------------------------
87
+//------------------------------------------------------------------------------
88
+//
89
+// Read/Write table
90
+//
91
+
92
+// To write table value 42 to 127 (coarse) 64 (fine)
93
+//
94
+// w 8 kTable_Addr_idx 42
95
+// w 8 kTable_Coarse_idx 127
96
+// w 8 kTable_fine_idx 64
97
+//
98
+// TO read table value 42
99
+// w 8 kTable_Addr_idx 42
100
+// r 8 kTable_Coarse_idx -> 127
101
+// r 8 kTable_Fine_idx   ->  64
102
+
103
+
104
+#define eeprom_addr( addr ) (kMax_idx + (addr))
105
+
106
+void table_write_cur_value( void )
107
+{
108
+  uint8_t tbl_addr = ctl_regs[ kTable_Addr_idx ] * 2;
109
+  
110
+  table[ tbl_addr+0 ] = ctl_regs[ kTable_Coarse_idx ];
111
+  table[ tbl_addr+1 ] = ctl_regs[ kTable_Fine_idx ];
112
+
113
+  EEPROM_write( eeprom_addr( tbl_addr+0 ), ctl_regs[ kTable_Coarse_idx ] );
114
+  EEPROM_write( eeprom_addr( tbl_addr+1 ), ctl_regs[ kTable_Fine_idx ]); 
115
+}
116
+
117
+void table_load( void )
118
+{
119
+  uint8_t i = 0;
120
+
121
+  for(; i<128; ++i)
122
+  {
123
+    uint8_t tbl_addr  = i*2;
124
+    table[tbl_addr+0] = EEPROM_read( eeprom_addr(tbl_addr+0) );
125
+    table[tbl_addr+1] = EEPROM_read( eeprom_addr(tbl_addr+1) );
126
+  }  
127
+}
128
+
129
+void restore_memory_from_eeprom( void )
130
+{
131
+  /*
132
+  uint8_t i;
133
+  for(i=0; i<kMax_idx; ++i)
134
+  {
135
+    ctl_regs[i] = EEPROM_read( eeprom_addr( i ) );
136
+  }
137
+  */
138
+  
139
+  table_load();
140
+}
141
+
142
+
143
+//------------------------------------------------------------------------------
144
+//------------------------------------------------------------------------------
145
+//------------------------------------------------------------------------------
146
+//
147
+// Timer0
148
+//
149
+
150
+volatile uint8_t tmr0_state        = 0;    // 0=disabled 1=coarse mode, 2=fine mode 
151
+volatile uint8_t tmr0_coarse_cur   = 0;
152
+
153
+// Use the current tmr0 ctl_reg[] values to set the timer to the starting state.
154
+void tmr0_reset()
155
+{
156
+  // if a coarse count exists then go into coarse mode 
157
+  if( ctl_regs[kTmr0_Coarse_idx] > 0 )
158
+  {
159
+    tmr0_state = 1;
160
+    OCR0A      = 0xff;
161
+  }
162
+  else // otherwise go into fine mode
163
+  {
164
+    tmr0_state = 2;
165
+    OCR0A     = ctl_regs[kTmr0_Fine_idx];
166
+  }
167
+  
168
+  tmr0_coarse_cur = 0;  
169
+}
170
+
171
+ISR(TIMER0_COMPA_vect)
172
+{
173
+  switch( tmr0_state )
174
+  {
175
+    case 0:
176
+      // disabled
177
+      break;
178
+
179
+    case 1: 
180
+      // coarse mode
181
+      if( ++tmr0_coarse_cur >= ctl_regs[kTmr0_Coarse_idx] )
182
+      {
183
+        tmr0_state  = 2;
184
+        OCR0A     = ctl_regs[kTmr0_Fine_idx];        
185
+      }
186
+      break;
187
+
188
+    case 2:
189
+      // fine mode
190
+      PINB = _BV(PINB4);  // writes to PINB toggle the pins
191
+
192
+      tmr0_reset(); // restart the timer 
193
+      break;
194
+  }
195
+}
196
+
197
+
198
+void timer0_init()
199
+{
200
+  TIMSK  &= ~_BV(OCIE0A);    // Disable interrupt TIMER1_OVF
201
+  TCCR0A  |=  0x02;           // CTC mode
202
+  TCCR0B  |= ctl_regs[kTmr0_Prescale_idx]; // set the prescaler
203
+
204
+  GTCCR  |= _BV(PSR0);      // Set the pre-scaler to the selected value
205
+  
206
+  tmr0_reset();              // set the timers starting state
207
+  
208
+  TIMSK  |= _BV(OCIE0A);     // Enable interrupt TIMER1_OVF  
209
+
210
+}
211
+
212
+
213
+//------------------------------------------------------------------------------
214
+//------------------------------------------------------------------------------
215
+//------------------------------------------------------------------------------
216
+//
217
+// PWM1
218
+//
219
+// PWM is optimized to use pins OC1A ,~OC1A, OC1B, ~OC1B but this code
220
+// but since these pins are not available this code uses
221
+// ISR's to redirect the output to PIN3
222
+
223
+void pwm1_update()
224
+{
225
+  OCR1B   = ctl_regs[kPWM1_Duty_idx]; // control duty cycle
226
+  OCR1C   = ctl_regs[kPWM1_Freq_idx]; // PWM frequency pre-scaler
227
+}
228
+
229
+
230
+
231
+ISR(TIMER1_OVF_vect)
232
+{
233
+  PORTB |= _BV(PINB3);  // set PWM pin
234
+}
235
+
236
+ISR(TIMER1_COMPB_vect)
237
+{
238
+  PORTB &= ~(_BV(PINB3)); // clear PWM pin
239
+}
240
+
241
+
242
+void pwm1_init()
243
+{
244
+  TIMSK  &= ~(_BV(OCIE1B) + _BV(TOIE1));    // Disable interrupts
245
+  
246
+  DDRB   |=  _BV(DDB3);  // setup PB3 as output  
247
+
248
+  // set on TCNT1 == 0     // happens when TCNT1 matches OCR1C
249
+  // clr on OCR1B == TCNT  // happens when TCNT1 matches OCR1B
250
+  //                       // COM1B1=1 COM1B0=0 (enable output on ~OC1B)
251
+  TCCR1  |= 9;             // 32us period (256 divider) prescaler
252
+  GTCCR  |= _BV(PWM1B);    // Enable PWM B and disconnect output pins
253
+  GTCCR  |= _BV(PSR1);     // Set the pre-scaler to the selected value
254
+
255
+  pwm1_update();
256
+
257
+  TIMSK  |= _BV(OCIE1B) + _BV(TOIE1);    // Enable interrupts
258
+
259
+
260
+  
261
+}
262
+
263
+//------------------------------------------------------------------------------
264
+//------------------------------------------------------------------------------
265
+//------------------------------------------------------------------------------
266
+
267
+// Tracks the current register pointer position
268
+volatile uint8_t reg_position = 0;
269
+const uint8_t    reg_size = sizeof(ctl_regs);
270
+
271
+//
272
+// Read Request Handler
273
+//
274
+// This is called for each read request we receive, never put more
275
+// than one byte of data (with TinyWireS.send) to the send-buffer when
276
+// using this callback
277
+//
278
+void on_request()
279
+{
280
+  uint8_t val = 0;
281
+  
282
+  switch( reg_position )
283
+  {
284
+    case kTable_Coarse_idx:
285
+      val = table[ ctl_regs[kTable_Addr_idx]*2 + 0 ];      
286
+      break;
287
+
288
+    case kTable_Fine_idx:
289
+      val = table[ ctl_regs[kTable_Addr_idx]*2 + 1 ];
290
+      break;
291
+      
292
+    default:
293
+      // read and transmit the requestd position
294
+      val = ctl_regs[reg_position];
295
+
296
+  }
297
+  
298
+  usiTwiTransmitByte(val);
299
+  
300
+  // Increment the reg position on each read, and loop back to zero
301
+  reg_position++;
302
+  if (reg_position >= reg_size)
303
+  {
304
+    reg_position = 0;
305
+  }
306
+  
307
+}
308
+
309
+
310
+//
311
+// The I2C data received -handler
312
+//
313
+// This needs to complete before the next incoming transaction (start,
314
+// data, restart/stop) on the bus does so be quick, set flags for long
315
+// running tasks to be called from the mainloop instead of running
316
+// them directly,
317
+//
318
+
319
+void on_receive( uint8_t byteN )
320
+{
321
+  PINB = _BV(PINB1);  // writes to PINB toggle the pins
322
+     
323
+    if (byteN < 1)
324
+    {
325
+        // Sanity-check
326
+        return;
327
+    }
328
+    if (byteN > TWI_RX_BUFFER_SIZE)
329
+    {
330
+        // Also insane number
331
+        return;
332
+    }
333
+
334
+    // get the register index to read/write
335
+    reg_position = usiTwiReceiveByte();
336
+    
337
+    byteN--;
338
+
339
+    // If only one byte was received then this was a read request
340
+    // and the buffer pointer (reg_position) is now set to return the byte
341
+    // at this location on the subsequent call to on_request() ...
342
+    if (!byteN)
343
+    {
344
+      return;
345
+    }
346
+
347
+    // ... otherwise this was a write request and the buffer
348
+    // pointer is now pointing to the first byte to write to
349
+    while(byteN--)
350
+    {
351
+      // write the value
352
+      ctl_regs[reg_position] = usiTwiReceiveByte();
353
+
354
+      // Set timer 1
355
+      if( kTmr0_Prescale_idx <= reg_position && reg_position <= kTmr0_Fine_idx )
356
+      { timer0_init(); }
357
+      else
358
+
359
+          
360
+        // Set PWM 1
361
+        if( kPWM1_Duty_idx <= reg_position && reg_position <= kPWM1_Freq_idx )
362
+        { pwm1_update(); }
363
+        else
364
+          
365
+
366
+          // Write table
367
+          if( reg_position == kTable_Fine_idx )
368
+          { table_write_cur_value(); }
369
+      
370
+      reg_position++;
371
+        
372
+      if (reg_position >= reg_size)
373
+      {
374
+        reg_position = 0;
375
+      }
376
+
377
+        
378
+    }
379
+
380
+  
381
+}
382
+
383
+
384
+
385
+int main(void)
386
+{
387
+  cli();        // mask all interupts
388
+
389
+
390
+  restore_memory_from_eeprom();
391
+  
392
+  DDRB  |=   _BV(DDB4)  + _BV(DDB3)  + _BV(DDB1);  // setup PB4,PB3,PB1 as output  
393
+  PORTB &= ~(_BV(PINB4) + _BV(PINB3) + _BV(PINB1)); // clear output pins
394
+
395
+  
396
+  timer0_init();
397
+  pwm1_init();
398
+  
399
+  // setup i2c library
400
+  usi_onReceiverPtr = on_receive; 
401
+  usi_onRequestPtr  = on_request;
402
+  usiTwiSlaveInit(I2C_SLAVE_ADDRESS);
403
+  
404
+  sei();
405
+
406
+  PINB = _BV(PINB1);  // writes to PINB toggle the pins
407
+  _delay_ms(1000);  
408
+  PINB = _BV(PINB1);  // writes to PINB toggle the pins
409
+
410
+  
411
+  while(1)
412
+  {
413
+    //_delay_ms(1000);
414
+
415
+    if (!usi_onReceiverPtr)
416
+    {
417
+        // no onReceive callback, nothing to do...
418
+      continue;
419
+    }
420
+    
421
+    if (!(USISR & ( 1 << USIPF )))
422
+    {
423
+        // Stop not detected
424
+      continue;
425
+    }
426
+
427
+    
428
+    uint8_t amount = usiTwiAmountDataInReceiveBuffer();
429
+    if (amount == 0)
430
+    {
431
+        // no data in buffer
432
+      continue;
433
+    }
434
+
435
+    
436
+    usi_onReceiverPtr(amount);
437
+
438
+    
439
+  }
440
+  return 0;
441
+}
442
+
443
+
444
+

+ 502
- 0
control/tiny/versions/i2c_timer_pwm_2.c 查看文件

@@ -0,0 +1,502 @@
1
+/*                                    
2
+                                    AT TINY 85
3
+                                     +--\/--+
4
+                              RESET _| 1  8 |_ +5V
5
+             ~OC1B       HOLD  DDB3 _| 2  7 |_ SCL
6
+              OC1B      ONSET  DDB4 _| 3  6 |_ DDB1 LED
7
+                                GND _| 4  5 |_ SDA
8
+                                     +------+
9
+        * = Serial and/or programming pins on Arduino as ISP
10
+*/
11
+
12
+
13
+// This program acts as the device (slave) for the control program i2c/a2a/c_ctl
14
+
15
+#define F_CPU 8000000L
16
+#include <stdio.h>
17
+#include <avr/io.h>
18
+#include <util/delay.h>
19
+#include <avr/interrupt.h>
20
+
21
+#include "usiTwiSlave.h"
22
+
23
+#define HOLD_DIR DDB3
24
+#define ATTK_DIR DDB4
25
+#define LED_DIR  DDB1
26
+
27
+#define HOLD_PIN PINB3
28
+#define ATTK_PIN PINB4
29
+#define LED_PIN  PINB1
30
+
31
+// Opcodes
32
+enum
33
+{ 
34
+ kSetReg_Op         =  0,  // Set register  <hi_addr> <lo_addr> <value0> ... <valueN>
35
+ kSetPwm_Op         =  1,  // Set PWM registers <enable> <duty> <freq>
36
+ kNoteOnVel_Op      =  2,  // Turn on note <vel>
37
+ kNoteOnUsec_Op     =  3,  // Turn on note <coarse> <fine>
38
+ kNoteOff_Op        =  4,  // Turn off note
39
+ kRead_Op           =  5,  // Read a value {{ <src>} <addr> }
40
+ kInvalid_Op        =  6
41
+};
42
+
43
+
44
+// Register addresses
45
+enum
46
+{
47
+ kTmr_Coarse_idx     =  0,  // Current Timer 0 coarse count
48
+ kTmr_Fine_idx       =  1,  // Current Timer 0 fine count
49
+ kTmr_Prescale_idx   =  2,  // Current Timer 0 clock divider: 1=1,2=8,3=64,4=256,5=1024
50
+ kPwm_Enable_idx     =  3,  // Current PWM 1 enable flag
51
+ kPwm_Duty_idx       =  4,  // Current PWM 1 duty cycle
52
+ kPwm_Freq_idx       =  5,  // Current PWM 1 frequency
53
+ kRead_Src_idx       =  6,  // 0=reg, 1=table, 2=eeprom
54
+ kReg_Addr_idx       =  7,  // Next Reg Address to read
55
+ kTable_Addr_idx     =  8,  // Next Table Address to read
56
+ kEE_Addr_idx        =  9,  // Next EEPROM address to read
57
+ kError_Code_idx     = 10,  // Error Code
58
+ kMax_idx
59
+};
60
+
61
+// Regster memory
62
+volatile uint8_t ctl_regs[] =
63
+{
64
+ 
65
+ 123,    //  1 (0-255)  Timer 0 Coarse Value 
66
+   8,    //  2 (0-255)  Timer 0 Fine Value
67
+   4,    //  0 (1-5)    4=32us per tick
68
+
69
+   1,    //  5 (0-1)   PWM1 Enable 
70
+ 127,    //  3 (0-255) PWM1 Duty cycle (0-100%)
71
+ 254,    //  4 (0-255) PWM1 Frequency  (123 hz)
72
+
73
+   0,    //  6 (0-255) Read Source 
74
+   0,    //  7 (0-255) Reg addr   
75
+   0,    //  8 (0-255) Table addr
76
+   0,    //  9 (0-255) EEPROM addr
77
+
78
+   0,    // 10 (0-255) Error code
79
+   
80
+};
81
+
82
+volatile uint8_t table[128];
83
+
84
+
85
+
86
+#define stackN 16 
87
+volatile uint8_t stack[ stackN ];
88
+
89
+//------------------------------------------------------------------------------
90
+//------------------------------------------------------------------------------
91
+//------------------------------------------------------------------------------
92
+//
93
+// EEPROM
94
+//
95
+
96
+void EEPROM_write(uint8_t ucAddress, uint8_t ucData)
97
+{
98
+  // Wait for completion of previous write 
99
+  while(EECR & (1<<EEPE))
100
+  {}
101
+    
102
+  EECR  = (0<<EEPM1)|(0<<EEPM0);      // Set Programming mode   
103
+  EEARH = 0;                          // Set up address and data registers
104
+  EEARL = ucAddress;
105
+  EEDR  = ucData;  
106
+  EECR |= (1<<EEMPE);                // Write logical one to EEMPE 
107
+  EECR |= (1<<EEPE);                 // Start eeprom write by setting EEPE 
108
+}
109
+
110
+
111
+uint8_t EEPROM_read(uint8_t ucAddress)
112
+{
113
+  // Wait for completion of previous write 
114
+  while(EECR & (1<<EEPE))
115
+  {}
116
+    
117
+  EEARH = 0;                          // Set up address and data registers
118
+  EEARL = ucAddress;
119
+  EECR |= (1<<EERE);                 // Start eeprom read by writing EERE 
120
+  return EEDR;                       // Return data from data register 
121
+}
122
+
123
+//------------------------------------------------------------------------------
124
+//------------------------------------------------------------------------------
125
+//------------------------------------------------------------------------------
126
+//
127
+// Read/Write table
128
+//
129
+
130
+#define eeprom_addr( addr ) (addr)
131
+
132
+
133
+void table_load( void )
134
+{
135
+  uint8_t i = 0;
136
+
137
+  for(; i<64; ++i)
138
+  {
139
+    uint16_t tbl_addr  = i*2;
140
+    table[tbl_addr+0] = EEPROM_read( eeprom_addr(tbl_addr+0) );
141
+    table[tbl_addr+1] = EEPROM_read( eeprom_addr(tbl_addr+1) );
142
+  }  
143
+}
144
+
145
+void restore_memory_from_eeprom( void )
146
+{
147
+  /*
148
+  uint8_t i;
149
+  for(i=0; i<kMax_idx; ++i)
150
+  {
151
+    ctl_regs[i] = EEPROM_read( eeprom_addr( i ) );
152
+  }
153
+  */
154
+  
155
+  table_load();
156
+}
157
+
158
+
159
+//------------------------------------------------------------------------------
160
+//------------------------------------------------------------------------------
161
+//------------------------------------------------------------------------------
162
+//
163
+// Timer0
164
+//
165
+
166
+volatile uint8_t tmr0_state        = 0;    // 0=disabled 1=coarse mode, 2=fine mode 
167
+volatile uint8_t tmr0_coarse_cur   = 0;
168
+
169
+// Use the current tmr0 ctl_reg[] values to set the timer to the starting state.
170
+void tmr0_reset()
171
+{
172
+  // if a coarse count exists then go into coarse mode 
173
+  if( ctl_regs[kTmr_Coarse_idx] > 0 )
174
+  {
175
+    tmr0_state = 1;
176
+    OCR0A      = 0xff;
177
+  }
178
+  else // otherwise go into fine mode
179
+  {
180
+    tmr0_state = 2;
181
+    OCR0A     = ctl_regs[kTmr_Fine_idx];
182
+  }
183
+  
184
+  tmr0_coarse_cur = 0;  
185
+}
186
+
187
+ISR(TIMER0_COMPA_vect)
188
+{
189
+  switch( tmr0_state )
190
+  {
191
+    case 0:
192
+      // disabled
193
+      break;
194
+
195
+    case 1: 
196
+      // coarse mode
197
+      if( ++tmr0_coarse_cur >= ctl_regs[kTmr_Coarse_idx] )
198
+      {
199
+        tmr0_state  = 2;
200
+        OCR0A     = ctl_regs[kTmr_Fine_idx];        
201
+      }
202
+      break;
203
+
204
+    case 2:
205
+      // fine mode
206
+      PINB = _BV(ATTK_PIN);  // writes to PINB toggle the pins
207
+
208
+      tmr0_reset(); // restart the timer 
209
+      break;
210
+  }
211
+}
212
+
213
+
214
+void timer0_init()
215
+{
216
+  TIMSK  &= ~_BV(OCIE0A);    // Disable interrupt TIMER0_COMPA_vect
217
+  TCCR0A  |=  0x02;           // CTC mode
218
+  TCCR0B  |= ctl_regs[kTmr_Prescale_idx]; // set the prescaler
219
+
220
+  GTCCR  |= _BV(PSR0);      // Set the pre-scaler to the selected value
221
+  
222
+  tmr0_reset();              // set the timers starting state
223
+  
224
+  TIMSK  |= _BV(OCIE0A);     // Enable interrupt TIMER0_COMPA_vect
225
+
226
+}
227
+
228
+
229
+
230
+
231
+
232
+//------------------------------------------------------------------------------
233
+//------------------------------------------------------------------------------
234
+//------------------------------------------------------------------------------
235
+//
236
+// PWM1
237
+//
238
+// PWM is optimized to use pins OC1A ,~OC1A, OC1B, ~OC1B but this code
239
+// but since these pins are not available this code uses
240
+// ISR's to redirect the output to PIN3
241
+
242
+void pwm1_update()
243
+{
244
+  OCR1B   = ctl_regs[kPwm_Duty_idx]; // control duty cycle
245
+  OCR1C   = ctl_regs[kPwm_Freq_idx]; // PWM frequency pre-scaler
246
+}
247
+
248
+ISR(TIMER1_OVF_vect)
249
+{
250
+    PORTB |= _BV(HOLD_PIN);  // set PWM pin
251
+}
252
+
253
+ISR(TIMER1_COMPB_vect)
254
+{
255
+  PORTB &= ~(_BV(HOLD_PIN)); // clear PWM pin
256
+}
257
+
258
+
259
+void pwm1_init()
260
+{
261
+  TIMSK  &= ~(_BV(OCIE1B) + _BV(TOIE1));    // Disable interrupts
262
+  
263
+  DDRB   |=  _BV(HOLD_DIR);  // setup PB3 as output  
264
+
265
+  // set on TCNT1 == 0     // happens when TCNT1 matches OCR1C
266
+  // clr on OCR1B == TCNT  // happens when TCNT1 matches OCR1B
267
+  //                       // COM1B1=1 COM1B0=0 (enable output on ~OC1B)
268
+  TCCR1  |= 9;             // 32us period (256 divider) prescaler
269
+  GTCCR  |= _BV(PWM1B);    // Enable PWM B and disconnect output pins
270
+  GTCCR  |= _BV(PSR1);     // Set the pre-scaler to the selected value
271
+
272
+  pwm1_update();
273
+
274
+  TIMSK  |= _BV(OCIE1B) + _BV(TOIE1);    // Enable interrupts
275
+
276
+
277
+  
278
+}
279
+
280
+//------------------------------------------------------------------------------
281
+//------------------------------------------------------------------------------
282
+//------------------------------------------------------------------------------
283
+
284
+
285
+//
286
+// Read Request Handler
287
+//
288
+// This is called for each read request we receive, never put more
289
+// than one byte of data (with TinyWireS.send) to the send-buffer when
290
+// using this callback
291
+//
292
+
293
+void on_request()
294
+{
295
+  uint8_t  val  = 0;
296
+
297
+  switch( ctl_regs[ kRead_Src_idx ] )
298
+  {
299
+    case 0:
300
+      val = table[ ctl_regs[ kReg_Addr_idx ] ];
301
+      ctl_regs[ kReg_Addr_idx ] += 1;
302
+      break;
303
+      
304
+    case 1:
305
+      val = table[ ctl_regs[ kTable_Addr_idx ] ];
306
+      ctl_regs[ kTable_Addr_idx ] += 1;
307
+      break;
308
+      
309
+    case 2:
310
+      val = EEPROM_read(ctl_regs[ kEE_Addr_idx]);
311
+      ctl_regs[ kEE_Addr_idx ] += 1;      
312
+  }
313
+  
314
+  usiTwiTransmitByte(val);
315
+
316
+}
317
+
318
+
319
+//
320
+// The I2C data received -handler
321
+//
322
+// This needs to complete before the next incoming transaction (start,
323
+// data, restart/stop) on the bus does so be quick, set flags for long
324
+// running tasks to be called from the mainloop instead of running
325
+// them directly,
326
+//
327
+
328
+void on_receive( uint8_t byteN )
329
+{
330
+  uint8_t stack_idx = 0;
331
+
332
+  PINB = _BV(LED_PIN);  // writes to PINB toggle the pins
333
+  
334
+  // Sanity-check
335
+  if( byteN < 1 || byteN > TWI_RX_BUFFER_SIZE)
336
+  {
337
+    // TODO: signal an error
338
+    return;
339
+  }
340
+
341
+  // get the command byte
342
+  uint8_t cur_op_id = usiTwiReceiveByte();
343
+    
344
+  --byteN;
345
+
346
+  // verify that cur_op_id is valid
347
+  if( cur_op_id < kInvalid_Op )
348
+  {
349
+    // TODO: signal an error
350
+    return;
351
+  }
352
+  
353
+  // get the command arguments
354
+  while(byteN--)
355
+  {
356
+    // write the value
357
+    stack[stack_idx] = usiTwiReceiveByte();
358
+
359
+    ++stack_idx;
360
+        
361
+    if(stack_idx >= stackN)
362
+    {
363
+      // TODO: signal an error
364
+      break;
365
+    }  
366
+  }
367
+
368
+  // execute the operation
369
+  switch( cur_op_id )
370
+  {
371
+    case kSetReg_Op:      // Set register  <reg> <value0> ... <valueN>
372
+      if( stack_idx > 1 )
373
+      {
374
+        uint8_t addr = stack[0];
375
+        uint8_t i = 2;
376
+        for(; i<stack_idx; ++i,++addr)
377
+          ctl_regs[ addr ] = stack[i];
378
+      }
379
+      break;
380
+
381
+    case kSetPwm_Op:     // Set pwm <enable>,<duty>,<freq>
382
+      {
383
+        uint8_t addr = kPwm_Enable_idx;
384
+        uint8_t i = 0;
385
+        for(; i<stack_idx; ++i,++addr)
386
+          ctl_regs[ addr ] = stack[i];
387
+        pwm1_update();
388
+      }
389
+      break;
390
+      
391
+    case kNoteOnVel_Op:   // Turn on note <vel>
392
+      if( stack_idx == 1 )
393
+      {
394
+        uint8_t addr = stack[0] >> 2; // divide by 2 (we have only 64 entries in the table)
395
+        
396
+        ctl_regs[ kTmr_Coarse_idx ] = table[ addr ];
397
+        ctl_regs[ kTmr_Fine_idx ]   = table[ addr+1 ];
398
+      }
399
+      tmr0_reset();
400
+      break;
401
+      
402
+    case kNoteOnUsec_Op:  // Turn on note <coarse> <fine>      
403
+      if( stack_idx == 2 )
404
+      {
405
+        ctl_regs[ kTmr_Coarse_idx ] = stack[0];
406
+        ctl_regs[ kTmr_Fine_idx ]   = stack[1];
407
+      }
408
+      tmr0_reset();
409
+      break;
410
+      
411
+    case kNoteOff_Op:     // Turn off note
412
+      PORTB &= ~(_BV(ATTK_PIN) + _BV(HOLD_PIN));
413
+      break;
414
+
415
+    case kRead_Op: // Read a value {{ <src>} <addr> }
416
+      if( stack_idx > 0)
417
+      {
418
+        ctl_regs[ kRead_Src_idx ] = stack[0];
419
+      }
420
+      
421
+      if( stack_idx > 1 )
422
+      {
423
+        uint8_t reg_addr = 4;
424
+        
425
+        switch( ctl_regs[ kRead_Src_idx ] )
426
+        {
427
+          case 0: reg_addr = kReg_Addr_idx;   break;
428
+          case 1: reg_addr = kTable_Addr_idx; break;
429
+          case 2: reg_addr = kEE_Addr_idx;    break;
430
+          default:
431
+            // TODO: signal error
432
+            break;
433
+        }
434
+
435
+        if( reg_addr <= 2 )
436
+          ctl_regs[ reg_addr ] = stack[1];
437
+
438
+        
439
+      }
440
+  } 
441
+}
442
+
443
+
444
+
445
+int main(void)
446
+{
447
+  cli();        // mask all interupts
448
+
449
+
450
+  DDRB  |=   _BV(ATTK_DIR) + _BV(HOLD_DIR) + _BV(LED_DIR);  // setup PB4,PB3,PB1 as output  
451
+  PORTB &= ~(_BV(ATTK_PIN) + _BV(HOLD_PIN) + _BV(LED_PIN)); // clear output pins
452
+
453
+  
454
+  timer0_init();
455
+  pwm1_init();
456
+  
457
+  // setup i2c library
458
+  usi_onReceiverPtr = on_receive; 
459
+  usi_onRequestPtr  = on_request;
460
+  usiTwiSlaveInit(I2C_SLAVE_ADDRESS);
461
+  
462
+  sei();
463
+
464
+  PINB = _BV(LED_PIN);  // writes to PINB toggle the pins
465
+  _delay_ms(1000);  
466
+  PINB = _BV(LED_PIN);  // writes to PINB toggle the pins
467
+
468
+  
469
+  while(1)
470
+  {
471
+    //_delay_ms(1000);
472
+
473
+    if (!usi_onReceiverPtr)
474
+    {
475
+      // no onReceive callback, nothing to do...
476
+      continue;
477
+    }
478
+    
479
+    if (!(USISR & ( 1 << USIPF )))
480
+    {
481
+      // Stop not detected
482
+      continue;
483
+    }
484
+
485
+    
486
+    uint8_t amount = usiTwiAmountDataInReceiveBuffer();
487
+    if (amount == 0)
488
+    {
489
+      // no data in buffer
490
+      continue;
491
+    }
492
+
493
+    
494
+    usi_onReceiverPtr(amount);
495
+
496
+    
497
+  }
498
+  return 0;
499
+}
500
+
501
+
502
+

+ 609
- 0
control/tiny/versions/i2c_timer_pwm_3.c 查看文件

@@ -0,0 +1,609 @@
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)
5
+/*                                    
6
+                                    AT TINY 85
7
+                                     +--\/--+
8
+                              RESET _| 1  8 |_ +5V
9
+             ~OC1B       HOLD  DDB3 _| 2  7 |_ SCL         yellow 
10
+              OC1B      ONSET  DDB4 _| 3  6 |_ DDB1 LED
11
+                                GND _| 4  5 |_ SDA         orange
12
+                                     +------+
13
+        * = Serial and/or programming pins on Arduino as ISP
14
+*/
15
+
16
+
17
+// This program acts as the device (slave) for the control program i2c/a2a/c_ctl
18
+#define F_CPU 16000000L
19
+
20
+#include <stdio.h>
21
+#include <avr/io.h>
22
+#include <util/delay.h>
23
+#include <avr/interrupt.h>
24
+
25
+#include "usiTwiSlave.h"
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
34
+
35
+// Opcodes
36
+enum
37
+{ 
38
+ 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
39
+ kNoteOnVel_Op      =  1,  // Turn on note          3 {<vel>}
40
+ kNoteOnUsec_Op     =  2,  // Turn on note          4 {<coarse> {<fine> {<prescale>}}}
41
+ kNoteOff_Op        =  3,  // Turn off note         5
42
+ kSetReadAddr_Op    =  4,  // Set a read addr.      6 {<src>} {<addr>} }  src: 0=reg 1=table 2=eeprom
43
+ kWrite_Op          =  5,  // Set write             7 {<addrfl|src> {addr}  {<value0> ... {<valueN>}}  addrFl:0x80  src: 4=reg 5=table 6=eeprom
44
+ kSetMode_Op        =  6,  // Set the mode flags    8 {<mode>}  1=repeat 2=pwm
45
+ kWriteTable_Op     =  7,  // Write table to EEprom 9 
46
+ kInvalid_Op        =  8   //                                             
47
+};
48
+
49
+
50
+enum
51
+{
52
+ kReg_Rd_Addr_idx    =  0,  // Next Reg Address to read
53
+ kTable_Rd_Addr_idx  =  1,  // Next Table Address to read
54
+ kEE_Rd_Addr_idx     =  2,  // Next EEPROM address to read
55
+ kRead_Src_idx       =  3,  // kReg_Rd_Addr_idx=reg,  kTable_Rd_Addr_idx=table, kEE_Rd_Addr_idx=eeprom
56
+ 
57
+ kReg_Wr_Addr_idx    =  4,  // Next Reg Address to write
58
+ kTable_Wr_Addr_idx  =  5,  // Next Table Address to write
59
+ kEE_Wr_Addr_idx     =  6,  // Next EEPROM address to write
60
+ kWrite_Dst_idx      =  7,  // kReg_Wr_Addr_idx=reg,  kTable_Wr_Addr_idx=table, kEE_Wr_Addr_idx=eeprom
61
+ 
62
+ kTmr_Coarse_idx     =  8,  //  
63
+ kTmr_Fine_idx       =  9,  // 
64
+ kTmr_Prescale_idx   = 10,  // Timer 0 clock divider: 1=1,2=8,3=64,4=256,5=1024  Default: 4 (16us)
65
+ 
66
+ kPwm_Duty_idx       = 11,  // 
67
+ kPwm_Freq_idx       = 12,  //
68
+ kPwm_Div_idx        = 13,  //
69
+
70
+ kMode_idx           = 14, // 1=repeat 2=pwm
71
+ kState_idx          = 15, // 1=attk 2=hold
72
+ kError_Code_idx     = 16, // Error Code
73
+ kMax_idx
74
+};
75
+
76
+enum
77
+{
78
+ kMode_Repeat_Fl = 1,
79
+ kMode_Pwm_Fl    = 2,
80
+ kState_Attk_Fl        = 1,
81
+ kState_Hold_Fl        = 2
82
+};
83
+
84
+
85
+#define isInRepeatMode() ctl_regs[ kMode_idx ] & kMode_Repeat_Fl
86
+#define isInPwmMode()    ctl_regs[ kMode_idx ] & kMode_Pwm_Fl
87
+
88
+// Flags:
89
+// 1=Repeat: 1=Timer and PWM are free running. This allows testing with LED's. 0=Timer triggers does not reset on time out. 
90
+// 2=PWM:  On timer timeout  1=PWM HOLD 0=Set HOLD 
91
+
92
+volatile uint8_t ctl_regs[] =
93
+{
94
+   0,                //  0 (0-(kMax_idx-1)) Reg Read Addr   
95
+   0,                //  1 (0-255)          Table Read Addr
96
+   0,                //  2 (0-255)          EE Read Addr  
97
+   kReg_Rd_Addr_idx, //  3 (0-2)    Read source
98
+   
99
+   0,                //  4 (0-(kMax_idx-1)) Reg Write Addr   
100
+   0,                //  5 (0-255)          Table Write Addr
101
+   0,                //  6 (0-255)          EE Write Addr
102
+   kReg_Wr_Addr_idx, //  7 (0-2)    Write source
103
+   
104
+ 245,                //  8 (0-255)  Timer 0 Coarse Value 
105
+  25,                //  9 (0-255)  Timer 0 Fine Value
106
+   4,                // 10 (1-5)    4=16us per tick
107
+   
108
+ 127,                // 11 (0-255)  Pwm Duty cycle
109
+ 254,                // 12 (0-255)  Pwm Frequency  (123 Hz)
110
+  10,                // 13 (0-15)   Pwm clock div 
111
+   
112
+   kMode_Repeat_Fl,  // 14 mode flags  1=Repeat 2=PWM
113
+   0,                // 15 state flags 1=attk   2=hold  (read/only)
114
+   0,                // 16 (0-255)  Error bit field    
115
+};
116
+
117
+// These registers are saved to Eeprom
118
+uint8_t eeprom_addr[] =
119
+{
120
+ kTmr_Prescale_idx,
121
+ kPwm_Duty_idx,
122
+ kPwm_Freq_idx,
123
+ kPwm_Div_idx
124
+};
125
+
126
+
127
+
128
+#define tableN 256
129
+uint8_t table[ tableN ]; // [ coarse_0,fine_0, coarse_1, fine_1, .... coarse_127,fine_127]
130
+ 
131
+
132
+enum
133
+{
134
+ kInvalid_Read_Src_ErrFl  = 0x01,
135
+ kInvalid_Write_Dst_ErrFl = 0x02
136
+};
137
+
138
+#define set_error( flag ) ctl_regs[ kError_Code_idx ] |= (flag)
139
+
140
+//------------------------------------------------------------------------------
141
+//------------------------------------------------------------------------------
142
+//------------------------------------------------------------------------------
143
+//
144
+// EEPROM
145
+//
146
+
147
+void EEPROM_write(uint8_t ucAddress, uint8_t ucData)
148
+{
149
+  // Wait for completion of previous write 
150
+  while(EECR & (1<<EEPE))
151
+  {}
152
+    
153
+  EECR = (0<<EEPM1)|(0<<EEPM0); // Set Programming mode   
154
+  EEAR = ucAddress;             // Set up address and data registers 
155
+  EEDR = ucData;  
156
+  EECR |= (1<<EEMPE);           // Write logical one to EEMPE 
157
+  EECR |= (1<<EEPE);            // Start eeprom write by setting EEPE 
158
+}
159
+
160
+uint8_t EEPROM_read(uint8_t ucAddress)
161
+{
162
+  // Wait for completion of previous write 
163
+  while(EECR & (1<<EEPE))
164
+  {}
165
+    
166
+  EEAR = ucAddress;  // Set up address register 
167
+  EECR |= (1<<EERE); // Start eeprom read by writing EERE 
168
+  return EEDR;       // Return data from data register 
169
+}
170
+
171
+void write_table()
172
+{
173
+  uint8_t i;
174
+  uint8_t regN = sizeof(eeprom_addr);
175
+
176
+  // write the persistent registers
177
+  for(i=0; i<regN; ++i)
178
+    EEPROM_write( i, ctl_regs[ eeprom_addr[i] ] );
179
+
180
+  // write the table
181
+  for(i=0; i<tableN; ++i)
182
+    EEPROM_write( regN+i, table[i] );
183
+}
184
+
185
+void load_table()
186
+{
187
+  uint8_t i;
188
+  uint8_t regN = sizeof(eeprom_addr);
189
+
190
+  // read the persistent registers
191
+  for(i=0; i<regN; ++i)
192
+    ctl_regs[ eeprom_addr[i] ] = EEPROM_read(i);
193
+
194
+  // read the tabke
195
+  for(i=0; i<tableN; ++i)
196
+    table[i] = EEPROM_read(regN + i);
197
+}
198
+
199
+
200
+//------------------------------------------------------------------------------
201
+//------------------------------------------------------------------------------
202
+//------------------------------------------------------------------------------
203
+//
204
+// Timer0
205
+//
206
+
207
+volatile uint8_t tmr0_state        = 0;    // current timer mode: 0=disabled 1=coarse mode, 2=fine mode 
208
+volatile uint8_t tmr0_coarse_cur   = 0;
209
+
210
+#define set_attack()    do { ctl_regs[kState_idx] |= kState_Attk_Fl;  PORTB |= _BV(ATTK_PIN);            } while(0)
211
+#define clear_attack()  do { PORTB &= ~_BV(ATTK_PIN);           ctl_regs[kState_idx] &= ~kState_Attk_Fl; } while(0)
212
+
213
+
214
+// Use the current tmr0 ctl_reg[] values to set the timer to the starting state.
215
+void tmr0_reset()
216
+{
217
+  tmr0_coarse_cur       = 0;               // clear the coarse time counter
218
+  ctl_regs[kState_idx] |= kState_Attk_Fl;  // set the attack state
219
+  PORTB                |= _BV(ATTK_PIN);   // set the attack pin 
220
+  
221
+  // if a coarse count exists then go into coarse mode 
222
+  if( ctl_regs[kTmr_Coarse_idx] > 0 )
223
+  {
224
+    tmr0_state = 1;
225
+    OCR0A      = 0xff;
226
+  }
227
+  else // otherwise go into fine mode
228
+  {
229
+    tmr0_state = 2;
230
+    OCR0A     = ctl_regs[kTmr_Fine_idx];
231
+  }
232
+  
233
+  TIMSK |= _BV(OCIE0A);     // enable the timer interrupt
234
+}
235
+
236
+ISR(TIMER0_COMPA_vect)
237
+{
238
+  switch( tmr0_state )
239
+  {
240
+    case 0:
241
+      // timer is disabled
242
+      break;
243
+
244
+    case 1: 
245
+      // coarse mode
246
+      if( ++tmr0_coarse_cur >= ctl_regs[kTmr_Coarse_idx] )
247
+      {
248
+        tmr0_state  = 2;
249
+        OCR0A     = ctl_regs[kTmr_Fine_idx];        
250
+      }
251
+      break;
252
+
253
+    case 2:
254
+      // fine mode
255
+
256
+      // This marks the end of a timer period 
257
+
258
+      // If in repeat mode ...
259
+      if(ctl_regs[kMode_idx] & kMode_Repeat_Fl)
260
+      {
261
+        // store the current state of the attack flag
262
+        uint8_t fl = ctl_regs[kState_idx] & kState_Attk_Fl;
263
+        
264
+        tmr0_reset();  // ... restart the timer
265
+        
266
+        // ATTK_PIN is always set after tmr0_reset() but we need to toggle in 'repeat' mode
267
+        if( fl )
268
+        {
269
+          clear_attack();
270
+        }
271
+
272
+        // In repeat mode we always run the PWM output continuously.
273
+        // This guarantees that no matter how the modes may be changing that PWM will be enabled.
274
+        TIMSK  |= _BV(OCIE1B) + _BV(TOIE1); // Enable PWM interrupts
275
+
276
+      }
277
+      else  // ... not in repeat mode
278
+      {
279
+        clear_attack();
280
+        
281
+        if( ctl_regs[kMode_idx] & kMode_Pwm_Fl)
282
+        {
283
+          TIMSK  |= _BV(OCIE1B) + _BV(TOIE1);    // PWM interupt Enable interrupts          
284
+        }
285
+        else
286
+        {
287
+          PORTB |= _BV(HOLD_PIN); // set the HOLD pin          
288
+        }
289
+
290
+        TIMSK &= ~_BV(OCIE0A);   // clear timer interrupt
291
+        
292
+      }
293
+      
294
+      break;
295
+  }
296
+}
297
+
298
+
299
+void tmr0_init()
300
+{
301
+  TIMSK  &= ~_BV(OCIE0A);                 // Disable interrupt TIMER1_OVF
302
+  TCCR0A  |=  0x02;                       // CTC mode
303
+  TCCR0B  |= ctl_regs[kTmr_Prescale_idx]; // set the prescaler
304
+  GTCCR   |= _BV(PSR0);                   // Set the pre-scaler to the selected value
305
+}
306
+
307
+
308
+//------------------------------------------------------------------------------
309
+//------------------------------------------------------------------------------
310
+//------------------------------------------------------------------------------
311
+//
312
+// Pwm
313
+//
314
+// PWM is optimized to use pins OC1A ,~OC1A, OC1B, ~OC1B
315
+// but since these pins are not available this code uses
316
+// ISR's to redirect the output to PIN3
317
+
318
+void pwm1_update()
319
+{
320
+  OCR1B   = ctl_regs[kPwm_Duty_idx]; // control duty cycle
321
+  OCR1C   = ctl_regs[kPwm_Freq_idx]; // PWM frequency pre-scaler
322
+}
323
+
324
+
325
+
326
+ISR(TIMER1_OVF_vect)
327
+{
328
+  PORTB |= _BV(HOLD_PIN);  // set PWM pin
329
+}
330
+
331
+ISR(TIMER1_COMPB_vect)
332
+{
333
+  PORTB &= ~(_BV(HOLD_PIN)); // clear PWM pin
334
+}
335
+
336
+
337
+void pwm1_init()
338
+{
339
+  TIMSK  &= ~(_BV(OCIE1B) + _BV(TOIE1));    // Disable interrupts
340
+  
341
+  DDRB   |=  _BV(HOLD_DIR);  // setup PB3 as output  
342
+
343
+  // set on TCNT1 == 0     // happens when TCNT1 matches OCR1C
344
+  // clr on OCR1B == TCNT  // happens when TCNT1 matches OCR1B
345
+  //                       // COM1B1=1 COM1B0=0 (enable output on ~OC1B)
346
+  TCCR1  |= ctl_regs[ kPwm_Div_idx];    // 32us period (512 divider) prescaler
347
+  GTCCR  |= _BV(PWM1B);    // Enable PWM B and disconnect output pins
348
+  GTCCR  |= _BV(PSR1);     // Set the pre-scaler to the selected value
349
+
350
+  pwm1_update();
351
+}
352
+
353
+//------------------------------------------------------------------------------
354
+//------------------------------------------------------------------------------
355
+//------------------------------------------------------------------------------
356
+
357
+// Tracks the current register pointer position
358
+volatile uint8_t reg_position = 0;
359
+const uint8_t    reg_size = sizeof(ctl_regs);
360
+
361
+//
362
+// Read Request Handler
363
+//
364
+// This is called for each read request we receive, never put more
365
+// than one byte of data (with TinyWireS.send) to the send-buffer when
366
+// using this callback
367
+//
368
+
369
+void on_request()
370
+{
371
+  uint8_t val = 0;
372
+  
373
+  switch( ctl_regs[ kRead_Src_idx ] )
374
+  {
375
+    case kReg_Rd_Addr_idx:
376
+      val = ctl_regs[ ctl_regs[kReg_Rd_Addr_idx] ];
377
+      break;
378
+
379
+    case kTable_Rd_Addr_idx:
380
+      val = table[ ctl_regs[kTable_Rd_Addr_idx] ];
381
+      break;
382
+
383
+    case kEE_Rd_Addr_idx:
384
+      val = EEPROM_read(ctl_regs[kEE_Rd_Addr_idx]);
385
+      break;
386
+
387
+    default:
388
+      set_error( kInvalid_Read_Src_ErrFl );
389
+      return;
390
+  }
391
+  
392
+  usiTwiTransmitByte(val);
393
+
394
+  ctl_regs[ ctl_regs[ kRead_Src_idx ]  ] += 1;
395
+
396
+}
397
+
398
+
399
+void _write_op( uint8_t* stack, uint8_t stackN )
400
+{
401
+  uint8_t stack_idx = 0;
402
+  
403
+  if( stackN > 0 )
404
+  {
405
+    uint8_t src     = stack[0] & 0x07;
406
+    uint8_t addr_fl = stack[0] & 0x08;
407
+
408
+    // verify the source value
409
+    if( src < kReg_Wr_Addr_idx  || src > kEE_Wr_Addr_idx )
410
+    {
411
+      set_error( kInvalid_Write_Dst_ErrFl );
412
+      return;
413
+    }
414
+
415
+    // set the write source
416
+    stack_idx                  = 1;
417
+    ctl_regs[ kWrite_Dst_idx ] = src;
418
+
419
+    // if an address value was passed also ....
420
+    if( addr_fl && stackN > 1 )
421
+    {
422
+      stack_idx       = 2;
423
+      ctl_regs[ src ] = stack[1];
424
+    }
425
+  }
426
+
427
+  //
428
+  for(; stack_idx<stackN; ++stack_idx)
429
+  {
430
+    uint8_t addr_idx = ctl_regs[ ctl_regs[kWrite_Dst_idx] ]++;
431
+    uint8_t val      = stack[ stack_idx ];
432
+    
433
+    switch( ctl_regs[ kWrite_Dst_idx ] )
434
+    {
435
+      case kReg_Wr_Addr_idx:   ctl_regs[ addr_idx ]           = val;  break;
436
+      case kTable_Wr_Addr_idx: table[ addr_idx ]              = val;  break;
437
+      case kEE_Wr_Addr_idx:    EEPROM_write( table[ addr_idx ], val); break;
438
+
439
+      default:
440
+        set_error( kInvalid_Write_Dst_ErrFl );
441
+        break;
442
+    }
443
+  }
444
+}
445
+
446
+//
447
+// The I2C data received -handler
448
+//
449
+// This needs to complete before the next incoming transaction (start,
450
+// data, restart/stop) on the bus does so be quick, set flags for long
451
+// running tasks to be called from the mainloop instead of running
452
+// them directly,
453
+//
454
+
455
+void on_receive( uint8_t byteN )
456
+{
457
+  PINB = _BV(LED_PIN);  // writes to PINB toggle the pins
458
+
459
+  const uint8_t stackN = 16;
460
+  uint8_t stack_idx = 0;
461
+  uint8_t stack[ stackN ];
462
+  uint8_t i;
463
+  
464
+  if (byteN < 1 || byteN > TWI_RX_BUFFER_SIZE)
465
+  {
466
+    // Sanity-check
467
+    return;
468
+  }
469
+
470
+  // get the register index to read/write
471
+  uint8_t op_id = usiTwiReceiveByte();
472
+    
473
+  byteN--;
474
+
475
+  // If only one byte was received then this was a read request
476
+  // and the buffer pointer (reg_position) is now set to return the byte
477
+  // at this location on the subsequent call to on_request() ...
478
+  if(byteN)
479
+  {
480
+    while( byteN-- )
481
+    {  
482
+      stack[stack_idx] = usiTwiReceiveByte();
483
+      ++stack_idx;
484
+    }
485
+  }
486
+  
487
+  switch( op_id )
488
+  {
489
+    case kSetPwm_Op:
490
+      for(i=0; i<stack_idx && i<3; ++i)
491
+        ctl_regs[ kPwm_Duty_idx + i ] = stack[i];
492
+
493
+      // if the PWM prescaler was changed
494
+      if( i == 3 )
495
+        pwm1_init();
496
+          
497
+      pwm1_update();
498
+      break;
499
+
500
+      
501
+    case kNoteOnUsec_Op:
502
+      for(i=0; i<stack_idx && i<3; ++i)
503
+        ctl_regs[ kTmr_Coarse_idx + i ] = stack[i];
504
+
505
+      // if a prescaler was included then the timer needs to be re-initialized
506
+      if( i == 3 )
507
+        tmr0_init();
508
+      
509
+      tmr0_reset();
510
+      break;
511
+
512
+    case kNoteOff_Op:
513
+      TIMSK  &= ~_BV(OCIE0A);                // clear timer interrupt (shouldn't be necessary)
514
+      TIMSK  &= ~(_BV(OCIE1B) + _BV(TOIE1)); // PWM interupt disable interrupts          
515
+      PORTB  &= ~_BV(HOLD_PIN);              // clear the HOLD pin
516
+      break;
517
+
518
+    case kSetReadAddr_Op:
519
+      if( stack_idx > 0 )
520
+      {
521
+        ctl_regs[ kRead_Src_idx ] = stack[0];
522
+      
523
+        if( stack_idx > 1 )
524
+          ctl_regs[ ctl_regs[ kRead_Src_idx ] ] = stack[1];
525
+      }
526
+      break;
527
+
528
+    case kWrite_Op:
529
+      _write_op( stack, stack_idx );
530
+      break;
531
+
532
+    case kSetMode_Op:
533
+      if( stack_idx > 0)
534
+      {
535
+        ctl_regs[ kMode_idx ] = stack[0];
536
+
537
+        // if repeat mode was enabled
538
+        if( ctl_regs[ kMode_idx ] & kMode_Repeat_Fl )
539
+          tmr0_reset();
540
+        
541
+        pwm1_init();  // the state of PWM may have been changed
542
+      }
543
+      break;
544
+
545
+    case kWriteTable_Op:
546
+      write_table();
547
+      break;
548
+  }
549
+}
550
+
551
+
552
+int main(void)
553
+{
554
+  cli();        // mask all interupts
555
+
556
+  DDRB  |=   _BV(ATTK_DIR)  + _BV(HOLD_DIR)  + _BV(LED_DIR);  // setup PB4,PB3,PB1 as output  
557
+  PORTB &= ~(_BV(ATTK_PIN)  + _BV(HOLD_PIN)  + _BV(LED_PIN)); // clear output pins
558
+  
559
+  tmr0_init();
560
+  pwm1_init();
561
+  
562
+  // setup i2c library
563
+  usi_onReceiverPtr = on_receive; 
564
+  usi_onRequestPtr  = on_request;
565
+  usiTwiSlaveInit(I2C_SLAVE_ADDRESS);
566
+  
567
+  sei();
568
+
569
+  PINB = _BV(LED_PIN);  // writes to PINB toggle the pins
570
+  _delay_ms(1000);  
571
+  PINB = _BV(LED_PIN);  // writes to PINB toggle the pins
572
+
573
+  // if in repeat mode
574
+  if( ctl_regs[ kMode_idx ] & kMode_Repeat_Fl)
575
+    tmr0_reset();
576
+  
577
+  while(1)
578
+  {
579
+
580
+    if (!usi_onReceiverPtr)
581
+    {
582
+        // no onReceive callback, nothing to do...
583
+      continue;
584
+    }
585
+    
586
+    if (!(USISR & ( 1 << USIPF )))
587
+    {
588
+        // Stop not detected
589
+      continue;
590
+    }
591
+
592
+    
593
+    uint8_t amount = usiTwiAmountDataInReceiveBuffer();
594
+    if (amount == 0)
595
+    {
596
+        // no data in buffer
597
+      continue;
598
+    }
599
+
600
+    
601
+    usi_onReceiverPtr(amount);
602
+
603
+    
604
+  }
605
+  return 0;
606
+}
607
+
608
+
609
+

Loading…
取消
儲存