소스 검색

Added picadae/

master
kevin.larke 4 년 전
커밋
b018a107d2
10개의 변경된 파일2142개의 추가작업 그리고 0개의 파일을 삭제
  1. 285
    0
      control/app/picadae_cmd.py
  2. 8
    0
      control/app/picadae_cmd.yml
  3. 23
    0
      control/ctrl/Makefile
  4. 237
    0
      control/ctrl/main.c
  5. 572
    0
      control/ctrl/twi.c
  6. 55
    0
      control/ctrl/twi.h
  7. 28
    0
      control/tiny/Makefile
  8. 177
    0
      control/tiny/i2c_timer_pwm.c
  9. 660
    0
      control/tiny/usiTwiSlave.c
  10. 97
    0
      control/tiny/usiTwiSlave.h

+ 285
- 0
control/app/picadae_cmd.py 파일 보기

@@ -0,0 +1,285 @@
1
+import os,sys,argparse,yaml,types,select,serial,logging,time
2
+
3
+from multiprocessing import Process, Pipe
4
+
5
+# Message header id's for messages passed between the application
6
+# process and the microcontroller and video processes
7
+QUIT_MSG   = 0xffff   
8
+DATA_MSG   = 0xfffe
9
+ERROR_MSG  = 0xfffd
10
+
11
+
12
+def _reset_port(port):
13
+    port.reset_input_buffer()
14
+    port.reset_output_buffer()
15
+    port.send_break()
16
+    #self.reportResetFl  = True
17
+    #self.reportStatusFl = True
18
+
19
+def _serial_process_func( serial_dev, baud, sensor_count, pipe ):
20
+
21
+    reset_N     = 0
22
+    drop_N      = 0
23
+    noSync_N    = 0
24
+    
25
+    with serial.Serial(serial_dev, baud) as port:
26
+
27
+        while True:
28
+
29
+            # get the count of available bytes in the serial port buffer
30
+            bytes_waiting_N = port.in_waiting
31
+
32
+
33
+            # if no serial port bytes are available then sleep ....
34
+            if bytes_waiting_N == 0:                    
35
+                time.sleep(0.01)  # ... for 10 ms
36
+
37
+            else: # read the serial port ...
38
+                v = port.read(bytes_waiting_N)
39
+
40
+                pipe.send((DATA_MSG,v)) # ... and send it to the parent
41
+
42
+                            
43
+            
44
+            msg = None
45
+            if pipe.poll():  # non-blocking check for parent process messages
46
+                try:
47
+                    msg = pipe.recv()
48
+                except EOFError:
49
+                    break
50
+                
51
+            # if an incoming message was received
52
+            if msg != None:
53
+
54
+                # this is a shutdown msg
55
+                if msg[0] == QUIT_MSG:
56
+                    pipe.send(msg) # ... send quit msg back
57
+                    break
58
+
59
+                # this is a data xmit msg
60
+                elif msg[0] == DATA_MSG:
61
+                    port.write(msg[1])
62
+                
63
+
64
+
65
+
66
+
67
+class SessionProcess(Process):
68
+    def __init__(self,target,name,args=()):
69
+        self.parent_end, child_end = Pipe()
70
+        super(SessionProcess, self).__init__(target=target,name=name,args=args + (child_end,))
71
+        self.doneFl    = False
72
+        
73
+    def quit(self):
74
+        # send quit msg to the child process
75
+        self.parent_end.send((QUIT_MSG,0))
76
+
77
+    def send(self,msg_id,value):
78
+        # send a msg to the child process
79
+        self.parent_end.send((msg_id,value))
80
+
81
+    def recv(self):
82
+        x = None
83
+        if not self.doneFl and self.parent_end.poll():
84
+            x = self.parent_end.recv()
85
+            
86
+            if x[0] == QUIT_MSG:
87
+                self.doneFl = True
88
+            
89
+        return x
90
+    
91
+    def isDone(self):
92
+        return self.doneFl
93
+
94
+class SerialProcess(SessionProcess):
95
+    def __init__(self,serial_device,baud,foo):
96
+        super(SerialProcess, self).__init__(_serial_process_func,"Serial",args=(serial_device,baud,foo))
97
+
98
+    
99
+
100
+class App:
101
+    def __init__( self, cfg ):
102
+
103
+        self.cfg       = cfg
104
+        self.serialProc  = SerialProcess(cfg.serial_dev,cfg.serial_baud,0)
105
+
106
+
107
+    def _update( self, quittingFl=False ):
108
+
109
+        if self.serialProc.isDone():
110
+            return False
111
+
112
+        while True:
113
+            msg = serialProc.recv()
114
+
115
+            # no serial msg's were received
116
+            if msg is None:
117
+                break
118
+
119
+            if msg[0] == DATA_MSG:
120
+                print("in:",msg[1])
121
+
122
+
123
+    def _parse_error( self, msg ):
124
+        return (None,msg)
125
+
126
+    def _parse_int( self, token, var_label, max_value ):
127
+        # convert the i2c destination address to an integer
128
+        try:
129
+            int_value = int(token)
130
+        except ValueError:
131
+            return self._parse_error("Synax error: '{}' is not a legal integer.".format(token))
132
+
133
+        # validate the i2c address value
134
+        if 0 > int_value or int_value > max_value:
135
+            return self._parse_error("Syntax error: '{}' {} out of range 0 to {}.".format(token,int_value,max_value))
136
+
137
+        return (int_value,None)
138
+    
139
+    def parse_cmd( self, cmd_str ):
140
+
141
+        op_tok_idx  = 0
142
+        i2c_tok_idx = 1
143
+        reg_tok_idx = 2
144
+        rdn_tok_idx = 3
145
+        
146
+        cmd_str.strip()
147
+
148
+        # convert the command string to tokens
149
+        tokenL = cmd_str.split(' ')
150
+
151
+        # no commands require fewer than 4 tokens
152
+        if len(tokenL) < 4:
153
+            return self._parse_error("Syntax error: Missing tokens.")
154
+
155
+        # get the command opcode
156
+        op_code = tokenL[ op_tok_idx ]
157
+
158
+        # validate the opcode
159
+        if op_code not in [ 'r','w']:
160
+            return self._parse_error("Unrecognized opcode: {}".format( op_code ))
161
+
162
+        # validate the token count given the opcode
163
+        if op_code == 'r' and len(tokenL) != 4:
164
+            return self._parse_error("Syntax error: Illegal read syntax.")
165
+
166
+        if op_code == 'w' and len(tokenL) == 4:
167
+            return self._parse_error("Syntax error: Illegal write command too short.")
168
+
169
+        # convert the i2c destination address to an integer
170
+        i2c_addr, msg = self._parse_int( tokenL[i2c_tok_idx], "i2c address", 127 )
171
+
172
+        if i2c_addr is None:
173
+            return (None,msg)
174
+
175
+        reg_addr, msg = self._parse_int( tokenL[reg_tok_idx], "reg address", 255 )
176
+
177
+        if reg_addr is None:
178
+            return (None,msg)
179
+
180
+        dataL      = []
181
+
182
+        # parse and validate the count of bytes to read
183
+        if op_code == 'r':
184
+            op_byteN, msg = self._parse_int( tokenL[ rdn_tok_idx ], "read byte count", 255 )
185
+
186
+            if op_byteN is None:
187
+                return (None,msg)
188
+
189
+            
190
+        # parse and validate the values to write    
191
+        elif op_code == 'w':
192
+
193
+            for j,i in enumerate(range(reg_tok_idx+1,len(tokenL))):
194
+                value, msg = self._parse_int( tokenL[i], "write value: %i" % (j), 255 )
195
+                
196
+                if value is None:
197
+                    return (None,msg)
198
+                
199
+                dataL.append(value)
200
+                
201
+            op_byteN = len(dataL)
202
+            
203
+
204
+        # form the command into a byte array
205
+        cmd_bV = bytearray( [ ord(op_code), i2c_addr, reg_addr, op_byteN ] + dataL )
206
+        
207
+        return (cmd_bV,None)
208
+
209
+        
210
+    def run( self ):
211
+
212
+        self.serialProc.start()
213
+        
214
+        print("'quit' to exit")
215
+        time_out_secs = 1
216
+        
217
+        while True:
218
+            
219
+            i, o, e = select.select( [sys.stdin], [], [], time_out_secs )
220
+
221
+            if (i):
222
+                s = sys.stdin.readline().strip()
223
+                
224
+                if s == 'quit':
225
+                    break
226
+                
227
+                cmd_bV,err_msg = self.parse_cmd(s)
228
+
229
+                if cmd_bV is None:
230
+                    print(err_msg)
231
+                else:
232
+                    self.serialProc.send( DATA_MSG, cmd_bV )
233
+                
234
+                
235
+            else:
236
+                # wait timed out
237
+                msg = self.serialProc.recv()
238
+
239
+                # if a serial msg was received
240
+                if msg is not None and msg[0] == DATA_MSG:
241
+                    print("ser:",msg[1])
242
+            
243
+            
244
+        self.serialProc.quit()
245
+
246
+def parse_args():
247
+    """Parse the command line arguments."""
248
+    
249
+    descStr  = """Picadae auto-calibrate."""
250
+    logL     = ['debug','info','warning','error','critical']
251
+    
252
+    ap = argparse.ArgumentParser(description=descStr)
253
+
254
+
255
+    ap.add_argument("-s","--setup",                     default="cfg/p_ac.yml",  help="YAML configuration file.")
256
+    ap.add_argument("-c","--cmd",   nargs="*",                                   help="Give a command as multiple tokens")
257
+    ap.add_argument("-r","--run",                                                help="Run a named command list from the setup file.")
258
+    ap.add_argument("-l","--log_level",choices=logL,     default="warning",      help="Set logging level: debug,info,warning,error,critical. Default:warning")
259
+
260
+    return ap.parse_args()
261
+    
262
+            
263
+def parse_yaml_cfg( fn ):
264
+    """Parse the YAML configuration file."""
265
+    
266
+    cfg  = None
267
+    
268
+    with open(fn,"r") as f:
269
+        cfgD = yaml.load(f, Loader=yaml.FullLoader)
270
+
271
+        cfg = types.SimpleNamespace(**cfgD['picadae_cmd'])
272
+
273
+    return cfg
274
+
275
+
276
+
277
+if __name__ == "__main__":
278
+
279
+    args = parse_args()
280
+
281
+    cfg = parse_yaml_cfg( args.setup )
282
+
283
+    app = App(cfg)
284
+
285
+    app.run()

+ 8
- 0
control/app/picadae_cmd.yml 파일 보기

@@ -0,0 +1,8 @@
1
+{
2
+ picadae_cmd:
3
+   {
4
+     serial_dev: "/dev/ttyACM0",
5
+     serial_baud: 38400,
6
+     
7
+   }
8
+}

+ 23
- 0
control/ctrl/Makefile 파일 보기

@@ -0,0 +1,23 @@
1
+ifndef TTY
2
+TTY=/dev/ttyACM0
3
+endif
4
+
5
+# compiler flags:
6
+# -Os                : optimize size
7
+# -DF_CPU=16000000UL : define F_CPU as 16Mghz
8
+# -mmcu=atmega328p   : target MCU
9
+
10
+main.hex : main.c
11
+	# compile to object file (optimize for size)
12
+	avr-gcc -Os -DF_CPU=16000000UL -mmcu=atmega328p  -o main.elf main.c twi.c
13
+	# link as ELF binary
14
+	#avr-gcc -mmcu=atmega328p main.o -o main.elf
15
+	# convert ELF format to an IHEX format as used by avrdude
16
+	avr-objcopy -O ihex -R .eeprom main.elf main.hex
17
+
18
+
19
+burn:
20
+	avrdude -F -V -c arduino -p ATMEGA328P -P $(TTY) -b 115200 -U flash:w:main.hex
21
+
22
+clean :
23
+	rm main.o twi.o main.elf main.hex

+ 237
- 0
control/ctrl/main.c 파일 보기

@@ -0,0 +1,237 @@
1
+// Note this program is designed to pair with c_client.
2
+// The i2c connection may be made directly between the two Arduino SDA and SCL pins.
3
+// No i2c pullup resistors are require.d
4
+#define F_CPU 16000000UL
5
+#define BAUD 38400
6
+
7
+#include <util/setbaud.h>
8
+#include <avr/io.h>
9
+#include <avr/interrupt.h>
10
+
11
+#include "twi.h"
12
+
13
+//------------------------------------------------------------------------------
14
+
15
+#define SER_BUF_N (16)  // size of receive buffer
16
+
17
+// Note that 'ser_buf_i_idx' must be declared volatile or the
18
+// the compare in the main loop will not work.
19
+volatile int  ser_buf_i_idx = 0;  // receive buffer input index
20
+int           ser_buf_o_idx = 0;  // receive buffer output index
21
+
22
+// Receive buffer
23
+char buf[ SER_BUF_N ];
24
+
25
+
26
+void uart_init(void)
27
+{
28
+    UBRR0H = UBRRH_VALUE;
29
+    UBRR0L = UBRRL_VALUE;
30
+
31
+#if USE_2X
32
+    UCSR0A |= _BV(U2X0);
33
+#else
34
+    UCSR0A &= ~(_BV(U2X0));
35
+#endif
36
+
37
+    UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); // 8-bit data 
38
+    UCSR0B = _BV(RXEN0) | _BV(TXEN0) | _BV(RXCIE0);   // Enable RX and TX and RX intertupt enable
39
+}
40
+
41
+void uart_putchar(char c)
42
+{
43
+  loop_until_bit_is_set(UCSR0A, UDRE0); // Wait until data register empty.
44
+  UDR0 = c;
45
+}
46
+
47
+void uart_putchar_alt(char c)
48
+{
49
+  UDR0 = c;
50
+  loop_until_bit_is_set(UCSR0A, TXC0); // Wait until transmission ready. 
51
+}
52
+
53
+char uart_getchar(void)
54
+{
55
+  loop_until_bit_is_set(UCSR0A, RXC0); // Wait until data exists. 
56
+  return UDR0;
57
+}
58
+
59
+//------------------------------------------------------------------------------
60
+
61
+#define I2C_LOCAL_ADDR  (9)
62
+#define I2C_REMOTE_ADDR (8)
63
+
64
+#define I2C_BUF_N (16)
65
+static          uint8_t i2c_buf[ I2C_BUF_N ]; 
66
+static volatile uint8_t i2c_buf_i_idx = 0;
67
+static          uint8_t i2c_buf_o_idx = 0;
68
+
69
+static          uint8_t last_char = '0';
70
+
71
+void i2c_read_from( uint8_t i2c_addr, uint8_t dev_reg_addr, uint8_t read_byte_cnt )
72
+{
73
+        uint8_t recv_char     = '0';  
74
+  const uint8_t kWaitFl       = 1;
75
+  const uint8_t kSendStopFl   = 1;
76
+  const uint8_t kNoSendStopFl = 0;
77
+
78
+  // Request to read from the client. Note that 'sendStop'==0.
79
+  // Use this call to tell the client what data should be sent
80
+  // during the subsequent twi_readFrom().
81
+  twi_writeTo(I2C_REMOTE_ADDR, &dev_reg_addr, 1, kWaitFl, kNoSendStopFl);
82
+
83
+      
84
+  // Blocking waiting and wait to read the client's response.
85
+  for( uint8_t i=0; i<read_byte_cnt; ++i)
86
+    if( twi_readFrom(I2C_REMOTE_ADDR, &recv_char, 1, i==read_byte_cnt-1) )
87
+      uart_putchar(recv_char);
88
+
89
+  PORTB ^= _BV(PORTB5);   //  toggle LED
90
+ 
91
+  
92
+}
93
+
94
+uint8_t i2c_xmit( uint8_t remote_addr, uint8_t* buf, uint8_t n, uint8_t sendStopFl)
95
+{
96
+  return twi_writeTo(remote_addr, buf, n, 1, sendStopFl);
97
+}
98
+
99
+void i2c_init()
100
+{
101
+  twi_setAddress(I2C_LOCAL_ADDR);
102
+  twi_init();
103
+}
104
+
105
+ISR(USART_RX_vect)
106
+{
107
+  // receive the incoming byte
108
+  buf[ ser_buf_i_idx ] = uart_getchar();
109
+
110
+  // advance the buffer input index
111
+  ser_buf_i_idx = (ser_buf_i_idx + 1) % SER_BUF_N;  
112
+}
113
+
114
+
115
+//--------------------------------------------------------------------------------------------------
116
+static volatile int timerFl = 0;
117
+  
118
+
119
+ISR(TIMER1_COMPA_vect)
120
+{
121
+  timerFl = 1;
122
+}
123
+
124
+void timer_init(void)
125
+{
126
+  TCCR1A = 0;              // set timer control registers to default
127
+  TCCR1B = 0;              // 
128
+  OCR1A = 15624;           // 1 Hz = 16Mghz / (1024 * 15624)
129
+  TCCR1B |= (1 << WGM12);  // CTC mode on
130
+  TCCR1B |= (1 << CS10);   // Set CS10 and CS12 bits for 1024 prescaler:
131
+  TCCR1B |= (1 << CS12);   // 
132
+  TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt  
133
+}
134
+
135
+//--------------------------------------------------------------------------------------------------
136
+
137
+
138
+int main (void)
139
+{
140
+  enum { kWait_for_cmd, kWait_for_i2c, kWait_for_reg, kWait_for_cnt, kWait_for_value };
141
+  const uint8_t kWaitFl       = 1;
142
+  const uint8_t kSendStopFl   = 1;
143
+  const uint8_t kNoSendStopFl = 0;
144
+  
145
+  char    c;
146
+  uint8_t state = kWait_for_cmd;
147
+  char    cmd;
148
+  uint8_t i2c_addr;
149
+  uint8_t dev_reg_addr;
150
+  uint8_t op_byte_cnt;
151
+  
152
+  cli();        // mask all interupts
153
+
154
+  DDRB |= _BV(DDB5);  // set led pin for output
155
+  
156
+  timer_init(); // setup the timer
157
+  uart_init();  // setup UART data format and baud rate
158
+  i2c_init();
159
+  sei();        // re-enable interrupts
160
+
161
+  uart_putchar('a');
162
+  
163
+  for(;;)
164
+  {
165
+    if( timerFl )
166
+    {
167
+      //PORTB ^= _BV(PORTB5);   //  toggle LED
168
+      
169
+      timerFl = 0;
170
+    }
171
+    
172
+    // if there are bytes waiting in the serial buffer
173
+    if( ser_buf_o_idx != ser_buf_i_idx )
174
+    {
175
+      // get the waiting byte
176
+      c = buf[ser_buf_o_idx];
177
+
178
+      // advance the buffer output index
179
+      ser_buf_o_idx = (ser_buf_o_idx+1) % SER_BUF_N;
180
+
181
+      //  Serial Protocol
182
+      //  'r', reg-idx, cnt,                      -> i2c_read_from()
183
+      //  'w', reg-idx, cnt, value0, ... valueN   -> i2c_xmit()
184
+      
185
+      switch(state)
186
+      {
187
+        case kWait_for_cmd:
188
+          if(c == 'w' || c == 'r')
189
+          {  
190
+            cmd   = c;
191
+            state = kWait_for_i2c;
192
+          }
193
+          else
194
+            uart_putchar('E');
195
+          break;
196
+
197
+        case kWait_for_i2c:
198
+          i2c_addr = (uint8_t)c;
199
+          state = kWait_for_reg;
200
+          break;
201
+          
202
+        case kWait_for_reg:
203
+          dev_reg_addr = (uint8_t)c;
204
+          state = kWait_for_cnt;
205
+          break;
206
+
207
+        case kWait_for_cnt:
208
+          op_byte_cnt = (uint8_t)c;
209
+          
210
+          if( cmd == 'r' )
211
+          {
212
+            i2c_read_from( i2c_addr, dev_reg_addr, op_byte_cnt );
213
+            state = kWait_for_cmd;
214
+          }
215
+          else
216
+          {
217
+            state = kWait_for_value;
218
+          }
219
+          break;
220
+            
221
+        case kWait_for_value:
222
+          {
223
+            uint8_t buf[] = { dev_reg_addr, c };
224
+                      
225
+            i2c_xmit( I2C_REMOTE_ADDR, buf, 2, kSendStopFl);
226
+            state = kWait_for_cmd;
227
+          }
228
+          break;
229
+            
230
+      }            
231
+    }        
232
+  }    
233
+}
234
+
235
+
236
+
237
+

+ 572
- 0
control/ctrl/twi.c 파일 보기

@@ -0,0 +1,572 @@
1
+/*
2
+  twi.c - TWI/I2C library for Wiring & Arduino
3
+  Copyright (c) 2006 Nicholas Zambetti.  All right reserved.
4
+
5
+  This library is free software; you can redistribute it and/or
6
+  modify it under the terms of the GNU Lesser General Public
7
+  License as published by the Free Software Foundation; either
8
+  version 2.1 of the License, or (at your option) any later version.
9
+
10
+  This library is distributed in the hope that it will be useful,
11
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
+  Lesser General Public License for more details.
14
+
15
+  You should have received a copy of the GNU Lesser General Public
16
+  License along with this library; if not, write to the Free Software
17
+  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
+
19
+  Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts
20
+*/
21
+
22
+#include <math.h>
23
+#include <stdlib.h>
24
+#include <inttypes.h>
25
+#include <avr/io.h>
26
+#include <avr/interrupt.h>
27
+#include <compat/twi.h>
28
+// kpl #include "Arduino.h" // for digitalWrite
29
+
30
+#define true (1)  // kpl
31
+#define false (0) // kpl
32
+
33
+#ifndef cbi
34
+#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
35
+#endif
36
+
37
+#ifndef sbi
38
+#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
39
+#endif
40
+
41
+//#include "pins_arduino.h"
42
+#include "twi.h"
43
+
44
+static volatile uint8_t twi_state;
45
+static volatile uint8_t twi_slarw;
46
+static volatile uint8_t twi_sendStop;			// should the transaction end with a stop
47
+static volatile uint8_t twi_inRepStart;			// in the middle of a repeated start
48
+
49
+static void (*twi_onSlaveTransmit)(void);
50
+static void (*twi_onSlaveReceive)(uint8_t*, int);
51
+
52
+static uint8_t twi_masterBuffer[TWI_BUFFER_LENGTH];
53
+static volatile uint8_t twi_masterBufferIndex;
54
+static volatile uint8_t twi_masterBufferLength;
55
+
56
+static uint8_t twi_txBuffer[TWI_BUFFER_LENGTH];
57
+static volatile uint8_t twi_txBufferIndex;
58
+static volatile uint8_t twi_txBufferLength;
59
+
60
+static uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH];
61
+static volatile uint8_t twi_rxBufferIndex;
62
+
63
+static volatile uint8_t twi_error;
64
+
65
+/* 
66
+ * Function twi_init
67
+ * Desc     readys twi pins and sets twi bitrate
68
+ * Input    none
69
+ * Output   none
70
+ */
71
+void twi_init(void)
72
+{
73
+  // initialize state
74
+  twi_state = TWI_READY;
75
+  twi_sendStop = true;		// default value
76
+  twi_inRepStart = false;
77
+  
78
+  // activate internal pullups for twi.
79
+  //kpl digitalWrite(SDA, 1);
80
+  //kpl digitalWrite(SCL, 1);
81
+  DDRC |= _BV(DDC4) + _BV(DDC5);  // kpl for atmega328  TODO: replace with sbi() macro and make cross-compilable
82
+  PORTC |= _BV(PORTC4) + _BV(PORTC5);  
83
+
84
+
85
+  
86
+  // initialize twi prescaler and bit rate
87
+  cbi(TWSR, TWPS0);
88
+  cbi(TWSR, TWPS1);
89
+  TWBR = ((F_CPU / TWI_FREQ) - 16) / 2;
90
+
91
+  /* twi bit rate formula from atmega128 manual pg 204
92
+  SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR))
93
+  note: TWBR should be 10 or higher for master mode
94
+  It is 72 for a 16mhz Wiring board with 100kHz TWI */
95
+
96
+  // enable twi module, acks, and twi interrupt
97
+  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
98
+}
99
+
100
+/* 
101
+ * Function twi_disable
102
+ * Desc     disables twi pins
103
+ * Input    none
104
+ * Output   none
105
+ */
106
+void twi_disable(void)
107
+{
108
+  // disable twi module, acks, and twi interrupt
109
+  TWCR &= ~(_BV(TWEN) | _BV(TWIE) | _BV(TWEA));
110
+
111
+  // deactivate internal pullups for twi.
112
+  // kpl digitalWrite(SDA, 0);
113
+  // kpl digitalWrite(SCL, 0);
114
+  DDRC &= ~(_BV(DDC4) + _BV(DDC5));  // kpl for atmega328 TODO: replace with cbi() macro and make cross-compilable
115
+  PORTC &= ~(_BV(PORTC4) + _BV(PORTC5));  
116
+
117
+  
118
+}
119
+
120
+/* 
121
+ * Function twi_slaveInit
122
+ * Desc     sets slave address and enables interrupt
123
+ * Input    none
124
+ * Output   none
125
+ */
126
+void twi_setAddress(uint8_t address)
127
+{
128
+  // set twi slave address (skip over TWGCE bit)
129
+  TWAR = address << 1;
130
+}
131
+
132
+/* 
133
+ * Function twi_setClock
134
+ * Desc     sets twi bit rate
135
+ * Input    Clock Frequency
136
+ * Output   none
137
+ */
138
+void twi_setFrequency(uint32_t frequency)
139
+{
140
+  TWBR = ((F_CPU / frequency) - 16) / 2;
141
+  
142
+  /* twi bit rate formula from atmega128 manual pg 204
143
+  SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR))
144
+  note: TWBR should be 10 or higher for master mode
145
+  It is 72 for a 16mhz Wiring board with 100kHz TWI */
146
+}
147
+
148
+/* 
149
+ * Function twi_readFrom
150
+ * Desc     attempts to become twi bus master and read a
151
+ *          series of bytes from a device on the bus
152
+ * Input    address: 7bit i2c device address
153
+ *          data: pointer to byte array
154
+ *          length: number of bytes to read into array
155
+ *          sendStop: Boolean indicating whether to send a stop at the end
156
+ * Output   number of bytes read
157
+ */
158
+uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop)
159
+{
160
+  uint8_t i;
161
+
162
+  // ensure data will fit into buffer
163
+  if(TWI_BUFFER_LENGTH < length){
164
+    return 0;
165
+  }
166
+
167
+  // wait until twi is ready, become master receiver
168
+  while(TWI_READY != twi_state){
169
+    continue;
170
+  }
171
+  twi_state = TWI_MRX;
172
+  twi_sendStop = sendStop;
173
+  // reset error state (0xFF.. no error occured)
174
+  twi_error = 0xFF;
175
+
176
+  // initialize buffer iteration vars
177
+  twi_masterBufferIndex = 0;
178
+  twi_masterBufferLength = length-1;  // This is not intuitive, read on...
179
+  // On receive, the previously configured ACK/NACK setting is transmitted in
180
+  // response to the received byte before the interrupt is signalled. 
181
+  // Therefor we must actually set NACK when the _next_ to last byte is
182
+  // received, causing that NACK to be sent in response to receiving the last
183
+  // expected byte of data.
184
+
185
+  // build sla+w, slave device address + w bit
186
+  twi_slarw = TW_READ;
187
+  twi_slarw |= address << 1;
188
+
189
+  if (true == twi_inRepStart) {
190
+    // if we're in the repeated start state, then we've already sent the start,
191
+    // (@@@ we hope), and the TWI statemachine is just waiting for the address byte.
192
+    // We need to remove ourselves from the repeated start state before we enable interrupts,
193
+    // since the ISR is ASYNC, and we could get confused if we hit the ISR before cleaning
194
+    // up. Also, don't enable the START interrupt. There may be one pending from the 
195
+    // repeated start that we sent ourselves, and that would really confuse things.
196
+    twi_inRepStart = false;			// remember, we're dealing with an ASYNC ISR
197
+    do {
198
+      TWDR = twi_slarw;
199
+    } while(TWCR & _BV(TWWC));
200
+    TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE);	// enable INTs, but not START
201
+  }
202
+  else
203
+    // send start condition
204
+    TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA);
205
+
206
+  // wait for read operation to complete
207
+  while(TWI_MRX == twi_state){
208
+    continue;
209
+  }
210
+
211
+  if (twi_masterBufferIndex < length)
212
+    length = twi_masterBufferIndex;
213
+
214
+  // copy twi buffer to data
215
+  for(i = 0; i < length; ++i){
216
+    data[i] = twi_masterBuffer[i];
217
+  }
218
+	
219
+  return length;
220
+}
221
+
222
+/* 
223
+ * Function twi_writeTo
224
+ * Desc     attempts to become twi bus master and write a
225
+ *          series of bytes to a device on the bus
226
+ * Input    address: 7bit i2c device address
227
+ *          data: pointer to byte array
228
+ *          length: number of bytes in array
229
+ *          wait: boolean indicating to wait for write or not
230
+ *          sendStop: boolean indicating whether or not to send a stop at the end
231
+ * Output   0 .. success
232
+ *          1 .. length to long for buffer
233
+ *          2 .. address send, NACK received
234
+ *          3 .. data send, NACK received
235
+ *          4 .. other twi error (lost bus arbitration, bus error, ..)
236
+ */
237
+uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait, uint8_t sendStop)
238
+{
239
+  uint8_t i;
240
+
241
+  // ensure data will fit into buffer
242
+  if(TWI_BUFFER_LENGTH < length){
243
+    return 1;
244
+  }
245
+
246
+  // wait until twi is ready, become master transmitter
247
+  while(TWI_READY != twi_state){
248
+    continue;
249
+  }
250
+  twi_state = TWI_MTX;
251
+  twi_sendStop = sendStop;
252
+  // reset error state (0xFF.. no error occured)
253
+  twi_error = 0xFF;
254
+
255
+  // initialize buffer iteration vars
256
+  twi_masterBufferIndex = 0;
257
+  twi_masterBufferLength = length;
258
+  
259
+  // copy data to twi buffer
260
+  for(i = 0; i < length; ++i){
261
+    twi_masterBuffer[i] = data[i];
262
+  }
263
+  
264
+  // build sla+w, slave device address + w bit
265
+  twi_slarw = TW_WRITE;
266
+  twi_slarw |= address << 1;
267
+  
268
+  // if we're in a repeated start, then we've already sent the START
269
+  // in the ISR. Don't do it again.
270
+  //
271
+  if (true == twi_inRepStart) {
272
+    // if we're in the repeated start state, then we've already sent the start,
273
+    // (@@@ we hope), and the TWI statemachine is just waiting for the address byte.
274
+    // We need to remove ourselves from the repeated start state before we enable interrupts,
275
+    // since the ISR is ASYNC, and we could get confused if we hit the ISR before cleaning
276
+    // up. Also, don't enable the START interrupt. There may be one pending from the 
277
+    // repeated start that we sent outselves, and that would really confuse things.
278
+    twi_inRepStart = false;			// remember, we're dealing with an ASYNC ISR
279
+    do {
280
+      TWDR = twi_slarw;				
281
+    } while(TWCR & _BV(TWWC));
282
+    TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE);	// enable INTs, but not START
283
+  }
284
+  else
285
+    // send start condition
286
+    TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTA);	// enable INTs
287
+
288
+  // wait for write operation to complete
289
+  while(wait && (TWI_MTX == twi_state)){
290
+    continue;
291
+  }
292
+  
293
+  if (twi_error == 0xFF)
294
+    return 0;	// success
295
+  else if (twi_error == TW_MT_SLA_NACK)
296
+    return 2;	// error: address send, nack received
297
+  else if (twi_error == TW_MT_DATA_NACK)
298
+    return 3;	// error: data send, nack received
299
+  else
300
+    return 4;	// other twi error
301
+}
302
+
303
+/* 
304
+ * Function twi_transmit
305
+ * Desc     fills slave tx buffer with data
306
+ *          must be called in slave tx event callback
307
+ * Input    data: pointer to byte array
308
+ *          length: number of bytes in array
309
+ * Output   1 length too long for buffer
310
+ *          2 not slave transmitter
311
+ *          0 ok
312
+ */
313
+uint8_t twi_transmit(const uint8_t* data, uint8_t length)
314
+{
315
+  uint8_t i;
316
+
317
+  // ensure data will fit into buffer
318
+  if(TWI_BUFFER_LENGTH < (twi_txBufferLength+length)){
319
+    return 1;
320
+  }
321
+  
322
+  // ensure we are currently a slave transmitter
323
+  if(TWI_STX != twi_state){
324
+    return 2;
325
+  }
326
+  
327
+  // set length and copy data into tx buffer
328
+  for(i = 0; i < length; ++i){
329
+    twi_txBuffer[twi_txBufferLength+i] = data[i];
330
+  }
331
+  twi_txBufferLength += length;
332
+  
333
+  return 0;
334
+}
335
+
336
+/* 
337
+ * Function twi_attachSlaveRxEvent
338
+ * Desc     sets function called before a slave read operation
339
+ * Input    function: callback function to use
340
+ * Output   none
341
+ */
342
+void twi_attachSlaveRxEvent( void (*function)(uint8_t*, int) )
343
+{
344
+  twi_onSlaveReceive = function;
345
+}
346
+
347
+/* 
348
+ * Function twi_attachSlaveTxEvent
349
+ * Desc     sets function called before a slave write operation
350
+ * Input    function: callback function to use
351
+ * Output   none
352
+ */
353
+void twi_attachSlaveTxEvent( void (*function)(void) )
354
+{
355
+  twi_onSlaveTransmit = function;
356
+}
357
+
358
+/* 
359
+ * Function twi_reply
360
+ * Desc     sends byte or readys receive line
361
+ * Input    ack: byte indicating to ack or to nack
362
+ * Output   none
363
+ */
364
+void twi_reply(uint8_t ack)
365
+{
366
+  // transmit master read ready signal, with or without ack
367
+  if(ack){
368
+    TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);
369
+  }else{
370
+	  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT);
371
+  }
372
+}
373
+
374
+/* 
375
+ * Function twi_stop
376
+ * Desc     relinquishes bus master status
377
+ * Input    none
378
+ * Output   none
379
+ */
380
+void twi_stop(void)
381
+{
382
+  // send stop condition
383
+  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO);
384
+
385
+  // wait for stop condition to be exectued on bus
386
+  // TWINT is not set after a stop condition!
387
+  while(TWCR & _BV(TWSTO)){
388
+    continue;
389
+  }
390
+
391
+  // update twi state
392
+  twi_state = TWI_READY;
393
+}
394
+
395
+/* 
396
+ * Function twi_releaseBus
397
+ * Desc     releases bus control
398
+ * Input    none
399
+ * Output   none
400
+ */
401
+void twi_releaseBus(void)
402
+{
403
+  // release bus
404
+  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT);
405
+
406
+  // update twi state
407
+  twi_state = TWI_READY;
408
+}
409
+
410
+ISR(TWI_vect)
411
+{
412
+  switch(TW_STATUS){
413
+    // All Master
414
+    case TW_START:     // sent start condition
415
+    case TW_REP_START: // sent repeated start condition
416
+      // copy device address and r/w bit to output register and ack
417
+      TWDR = twi_slarw;
418
+      twi_reply(1);
419
+      break;
420
+
421
+    // Master Transmitter
422
+    case TW_MT_SLA_ACK:  // slave receiver acked address
423
+    case TW_MT_DATA_ACK: // slave receiver acked data
424
+      // if there is data to send, send it, otherwise stop 
425
+      if(twi_masterBufferIndex < twi_masterBufferLength){
426
+        // copy data to output register and ack
427
+        TWDR = twi_masterBuffer[twi_masterBufferIndex++];
428
+        twi_reply(1);
429
+      }else{
430
+	if (twi_sendStop)
431
+          twi_stop();
432
+	else {
433
+	  twi_inRepStart = true;	// we're gonna send the START
434
+	  // don't enable the interrupt. We'll generate the start, but we 
435
+	  // avoid handling the interrupt until we're in the next transaction,
436
+	  // at the point where we would normally issue the start.
437
+	  TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ;
438
+	  twi_state = TWI_READY;
439
+	}
440
+      }
441
+      break;
442
+    case TW_MT_SLA_NACK:  // address sent, nack received
443
+      twi_error = TW_MT_SLA_NACK;
444
+      twi_stop();
445
+      break;
446
+    case TW_MT_DATA_NACK: // data sent, nack received
447
+      twi_error = TW_MT_DATA_NACK;
448
+      twi_stop();
449
+      break;
450
+    case TW_MT_ARB_LOST: // lost bus arbitration
451
+      twi_error = TW_MT_ARB_LOST;
452
+      twi_releaseBus();
453
+      break;
454
+
455
+    // Master Receiver
456
+    case TW_MR_DATA_ACK: // data received, ack sent
457
+      // put byte into buffer
458
+      twi_masterBuffer[twi_masterBufferIndex++] = TWDR;
459
+    case TW_MR_SLA_ACK:  // address sent, ack received
460
+      // ack if more bytes are expected, otherwise nack
461
+      if(twi_masterBufferIndex < twi_masterBufferLength){
462
+        twi_reply(1);
463
+      }else{
464
+        twi_reply(0);
465
+      }
466
+      break;
467
+    case TW_MR_DATA_NACK: // data received, nack sent
468
+      // put final byte into buffer
469
+      twi_masterBuffer[twi_masterBufferIndex++] = TWDR;
470
+	if (twi_sendStop)
471
+          twi_stop();
472
+	else {
473
+	  twi_inRepStart = true;	// we're gonna send the START
474
+	  // don't enable the interrupt. We'll generate the start, but we 
475
+	  // avoid handling the interrupt until we're in the next transaction,
476
+	  // at the point where we would normally issue the start.
477
+	  TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ;
478
+	  twi_state = TWI_READY;
479
+	}    
480
+	break;
481
+    case TW_MR_SLA_NACK: // address sent, nack received
482
+      twi_stop();
483
+      break;
484
+    // TW_MR_ARB_LOST handled by TW_MT_ARB_LOST case
485
+
486
+    // Slave Receiver
487
+    case TW_SR_SLA_ACK:   // addressed, returned ack
488
+    case TW_SR_GCALL_ACK: // addressed generally, returned ack
489
+    case TW_SR_ARB_LOST_SLA_ACK:   // lost arbitration, returned ack
490
+    case TW_SR_ARB_LOST_GCALL_ACK: // lost arbitration, returned ack
491
+      // enter slave receiver mode
492
+      twi_state = TWI_SRX;
493
+      // indicate that rx buffer can be overwritten and ack
494
+      twi_rxBufferIndex = 0;
495
+      twi_reply(1);
496
+      break;
497
+    case TW_SR_DATA_ACK:       // data received, returned ack
498
+    case TW_SR_GCALL_DATA_ACK: // data received generally, returned ack
499
+      // if there is still room in the rx buffer
500
+      if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){
501
+        // put byte in buffer and ack
502
+        twi_rxBuffer[twi_rxBufferIndex++] = TWDR;
503
+        twi_reply(1);
504
+      }else{
505
+        // otherwise nack
506
+        twi_reply(0);
507
+      }
508
+      break;
509
+    case TW_SR_STOP: // stop or repeated start condition received
510
+      // ack future responses and leave slave receiver state
511
+      twi_releaseBus();
512
+      // put a null char after data if there's room
513
+      if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){
514
+        twi_rxBuffer[twi_rxBufferIndex] = '\0';
515
+      }
516
+      // callback to user defined callback
517
+      twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex);
518
+      // since we submit rx buffer to "wire" library, we can reset it
519
+      twi_rxBufferIndex = 0;
520
+      break;
521
+    case TW_SR_DATA_NACK:       // data received, returned nack
522
+    case TW_SR_GCALL_DATA_NACK: // data received generally, returned nack
523
+      // nack back at master
524
+      twi_reply(0);
525
+      break;
526
+    
527
+    // Slave Transmitter
528
+    case TW_ST_SLA_ACK:          // addressed, returned ack
529
+    case TW_ST_ARB_LOST_SLA_ACK: // arbitration lost, returned ack
530
+      // enter slave transmitter mode
531
+      twi_state = TWI_STX;
532
+      // ready the tx buffer index for iteration
533
+      twi_txBufferIndex = 0;
534
+      // set tx buffer length to be zero, to verify if user changes it
535
+      twi_txBufferLength = 0;
536
+      // request for txBuffer to be filled and length to be set
537
+      // note: user must call twi_transmit(bytes, length) to do this
538
+      twi_onSlaveTransmit();
539
+      // if they didn't change buffer & length, initialize it
540
+      if(0 == twi_txBufferLength){
541
+        twi_txBufferLength = 1;
542
+        twi_txBuffer[0] = 0x00;
543
+      }
544
+      // transmit first byte from buffer, fall
545
+    case TW_ST_DATA_ACK: // byte sent, ack returned
546
+      // copy data to output register
547
+      TWDR = twi_txBuffer[twi_txBufferIndex++];
548
+      // if there is more to send, ack, otherwise nack
549
+      if(twi_txBufferIndex < twi_txBufferLength){
550
+        twi_reply(1);
551
+      }else{
552
+        twi_reply(0);
553
+      }
554
+      break;
555
+    case TW_ST_DATA_NACK: // received nack, we are done 
556
+    case TW_ST_LAST_DATA: // received ack, but we are done already!
557
+      // ack future responses
558
+      twi_reply(1);
559
+      // leave slave receiver state
560
+      twi_state = TWI_READY;
561
+      break;
562
+
563
+    // All
564
+    case TW_NO_INFO:   // no state information
565
+      break;
566
+    case TW_BUS_ERROR: // bus error, illegal stop/start
567
+      twi_error = TW_BUS_ERROR;
568
+      twi_stop();
569
+      break;
570
+  }
571
+}
572
+

+ 55
- 0
control/ctrl/twi.h 파일 보기

@@ -0,0 +1,55 @@
1
+/*
2
+  twi.h - TWI/I2C library for Wiring & Arduino
3
+  Copyright (c) 2006 Nicholas Zambetti.  All right reserved.
4
+
5
+  This library is free software; you can redistribute it and/or
6
+  modify it under the terms of the GNU Lesser General Public
7
+  License as published by the Free Software Foundation; either
8
+  version 2.1 of the License, or (at your option) any later version.
9
+
10
+  This library is distributed in the hope that it will be useful,
11
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
+  Lesser General Public License for more details.
14
+
15
+  You should have received a copy of the GNU Lesser General Public
16
+  License along with this library; if not, write to the Free Software
17
+  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
+*/
19
+
20
+#ifndef twi_h
21
+#define twi_h
22
+
23
+  #include <inttypes.h>
24
+
25
+  //#define ATMEGA8
26
+
27
+  #ifndef TWI_FREQ
28
+  #define TWI_FREQ 100000L
29
+  #endif
30
+
31
+  #ifndef TWI_BUFFER_LENGTH
32
+  #define TWI_BUFFER_LENGTH 32
33
+  #endif
34
+
35
+  #define TWI_READY 0
36
+  #define TWI_MRX   1
37
+  #define TWI_MTX   2
38
+  #define TWI_SRX   3
39
+  #define TWI_STX   4
40
+  
41
+  void twi_init(void);
42
+  void twi_disable(void);
43
+  void twi_setAddress(uint8_t);
44
+  void twi_setFrequency(uint32_t);
45
+  uint8_t twi_readFrom(uint8_t, uint8_t*, uint8_t, uint8_t);
46
+  uint8_t twi_writeTo(uint8_t, uint8_t*, uint8_t, uint8_t, uint8_t);
47
+  uint8_t twi_transmit(const uint8_t*, uint8_t);
48
+  void twi_attachSlaveRxEvent( void (*)(uint8_t*, int) );
49
+  void twi_attachSlaveTxEvent( void (*)(void) );
50
+  void twi_reply(uint8_t);
51
+  void twi_stop(void);
52
+  void twi_releaseBus(void);
53
+
54
+#endif
55
+

+ 28
- 0
control/tiny/Makefile 파일 보기

@@ -0,0 +1,28 @@
1
+ifndef TTY
2
+TTY=/dev/ttyACM0
3
+endif
4
+
5
+ifndef TARGET
6
+TARGET=blink
7
+endif
8
+
9
+MCU=attiny85
10
+AVRDUDEMCU=t85
11
+CC=/usr/bin/avr-gcc
12
+CFLAGS=-g -Os -Wall -mcall-prologues -mmcu=$(MCU)
13
+OBJ2HEX=/usr/bin/avr-objcopy
14
+AVRDUDE=avrdude
15
+
16
+# See http://www.engbedded.com/fusecalc for fuse settings
17
+# /usr/bin/avrdude -C/etc/avrdude/avrdude.conf -v -pattiny85 -cstk500v1 -P/dev/ttyACM0 -b19200 -Uflash:w:/tmp/arduino_build_108059/i2c.ino.hex:i 
18
+# 	
19
+
20
+all:
21
+	$(CC) $(CFLAGS) $(TARGET).c usiTwiSlave.c -o$(TARGET)
22
+	$(OBJ2HEX) -R .eeprom -O ihex $(TARGET) $(TARGET).hex
23
+
24
+burn:
25
+	$(AVRDUDE) -p $(MCU) -P $(TTY)  -C/etc/avrdude/avrdude.conf -v -c avrisp -b 19200 -U flash:w:$(TARGET).hex -U lfuse:w:0xe2:m -U hfuse:w:0xdf:m -U efuse:w:0xff:m
26
+clean:
27
+	rm -f *.hex *.obj *.o
28
+

+ 177
- 0
control/tiny/i2c_timer_pwm.c 파일 보기

@@ -0,0 +1,177 @@
1
+// This program acts as the device (slave) for the control program i2c/a2a/c_ctl
2
+#define F_CPU 8000000L
3
+#include <stdio.h>
4
+#include <avr/io.h>
5
+#include <util/delay.h>
6
+#include <avr/interrupt.h>
7
+
8
+#include "usiTwiSlave.h"
9
+
10
+#define I2C_SLAVE_ADDRESS 0x8 // the 7-bit address (remember to change this when adapting this example)
11
+
12
+enum
13
+{
14
+ kCS13_10_idx = 0,  // Timer 1 Prescalar (CS13,CS12,CS11,CS10) from Table 12-5 pg 89
15
+ kOCR1C_idx   = 1,  // OCR1C timer match value
16
+ 
17
+};
18
+
19
+volatile uint8_t ctl_regs[] =
20
+{
21
+ 0x0f,   // clk/16384
22
+ 244,    // OCR1C
23
+};
24
+
25
+// Tracks the current register pointer position
26
+volatile uint8_t reg_position = 0;
27
+const uint8_t reg_size = sizeof(ctl_regs);
28
+
29
+ISR(TIMER1_OVF_vect)
30
+{
31
+  PINB = _BV(PINB4);  // writes to PINB toggle the pins
32
+}
33
+
34
+void timer_init()
35
+{
36
+  TIMSK  &= ~_BV(TOIE1);    // Disable interrupt TIMER1_OVF
37
+  OCR1A   = 255;            // Set to anything greater than OCR1C (the counter never gets here.)
38
+  TCCR1  |= _BV(CTC1);      // Reset TCNT1 to 0 when TCNT1==OCR1C 
39
+  TCCR1  |= _BV(PWM1A);     // Enable PWM A
40
+  TCCR1  |= ctl_regs[kCS13_10_idx] & 0x0f;
41
+  OCR1C   = ctl_regs[kOCR1C_idx];
42
+  TIMSK  |= _BV(TOIE1);     // Enable interrupt TIMER1_OVF  
43
+}
44
+
45
+
46
+
47
+/**
48
+ * This is called for each read request we receive, never put more
49
+ * than one byte of data (with TinyWireS.send) to the send-buffer when
50
+ * using this callback
51
+ */
52
+void on_request()
53
+{
54
+  // read and transmit the requestd position
55
+  usiTwiTransmitByte(ctl_regs[reg_position]);
56
+
57
+  
58
+  // Increment the reg position on each read, and loop back to zero
59
+  reg_position++;
60
+  if (reg_position >= reg_size)
61
+  {
62
+    reg_position = 0;
63
+  }
64
+  
65
+}
66
+
67
+
68
+/**
69
+ * The I2C data received -handler
70
+ *
71
+ * This needs to complete before the next incoming transaction (start,
72
+ * data, restart/stop) on the bus does so be quick, set flags for long
73
+ * running tasks to be called from the mainloop instead of running
74
+ * them directly,
75
+ */
76
+
77
+void on_receive( uint8_t howMany )
78
+{
79
+    if (howMany < 1)
80
+    {
81
+        // Sanity-check
82
+        return;
83
+    }
84
+    if (howMany > TWI_RX_BUFFER_SIZE)
85
+    {
86
+        // Also insane number
87
+        return;
88
+    }
89
+
90
+    // get the register index to read/write
91
+    reg_position = usiTwiReceiveByte();
92
+    
93
+    howMany--;
94
+
95
+    // If only one byte was received then this was a read request
96
+    // and the buffer pointer (reg_position) is now set to return the byte
97
+    // at this location on the subsequent call to on_request() ...
98
+    if (!howMany)
99
+    {
100
+      return;
101
+    }
102
+
103
+    // ... otherwise this was a write request and the buffer
104
+    // pointer is now pointing to the first byte to write to
105
+    while(howMany--)
106
+    {
107
+        ctl_regs[reg_position] = usiTwiReceiveByte();
108
+
109
+        if(reg_position == kCS13_10_idx || reg_position == kOCR1C_idx )
110
+          timer_init();
111
+        
112
+        reg_position++;
113
+        if (reg_position >= reg_size)
114
+        {
115
+            reg_position = 0;
116
+        }
117
+    }
118
+  
119
+}
120
+
121
+
122
+
123
+int main(void)
124
+{
125
+  cli();        // mask all interupts
126
+    
127
+  DDRB  |= _BV(DDB4);  // setup PB4 as output
128
+  PORTB &= ~_BV(PINB4);
129
+
130
+  timer_init();
131
+
132
+  // setup i2c library
133
+  usi_onReceiverPtr = on_receive; //on_receive;
134
+  usi_onRequestPtr = on_request;
135
+  usiTwiSlaveInit(I2C_SLAVE_ADDRESS);
136
+  
137
+  sei();
138
+
139
+  PINB = _BV(PINB4);  // writes to PINB toggle the pins
140
+  _delay_ms(1000);  
141
+  PINB = _BV(PINB4);  // writes to PINB toggle the pins
142
+
143
+  
144
+  while(1)
145
+  {
146
+    //_delay_ms(1000);
147
+
148
+    if (!usi_onReceiverPtr)
149
+    {
150
+        // no onReceive callback, nothing to do...
151
+      continue;
152
+    }
153
+    
154
+    if (!(USISR & ( 1 << USIPF )))
155
+    {
156
+        // Stop not detected
157
+      continue;
158
+    }
159
+
160
+    
161
+    uint8_t amount = usiTwiAmountDataInReceiveBuffer();
162
+    if (amount == 0)
163
+    {
164
+        // no data in buffer
165
+      continue;
166
+    }
167
+
168
+    
169
+    usi_onReceiverPtr(amount);
170
+
171
+    
172
+  }
173
+  return 0;
174
+}
175
+
176
+
177
+

+ 660
- 0
control/tiny/usiTwiSlave.c 파일 보기

@@ -0,0 +1,660 @@
1
+/********************************************************************************
2
+
3
+USI TWI Slave driver.
4
+
5
+Created by Donald R. Blake. donblake at worldnet.att.net
6
+Adapted by Jochen Toppe, jochen.toppe at jtoee.com
7
+
8
+---------------------------------------------------------------------------------
9
+
10
+Created from Atmel source files for Application Note AVR312: Using the USI Module
11
+as an I2C slave.
12
+
13
+This program is free software; you can redistribute it and/or modify it under the
14
+terms of the GNU General Public License as published by the Free Software
15
+Foundation; either version 2 of the License, or (at your option) any later
16
+version.
17
+
18
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
19
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
20
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
21
+
22
+---------------------------------------------------------------------------------
23
+
24
+Change Activity:
25
+
26
+    Date       Description
27
+   ------      -------------
28
+  16 Mar 2007  Created.
29
+  27 Mar 2007  Added support for ATtiny261, 461 and 861.
30
+  26 Apr 2007  Fixed ACK of slave address on a read.
31
+  04 Jul 2007  Fixed USISIF in ATtiny45 def
32
+  12 Dev 2009  Added callback functions for data requests
33
+  06 Feb 2015  Minor change to allow mutli-byte requestFrom() from master.
34
+  10 Feb 2015  Simplied RX/TX buffer code and allowed use of full buffer.
35
+  12 Dec 2016  Added support for ATtiny167
36
+
37
+********************************************************************************/
38
+
39
+
40
+/********************************************************************************
41
+                                    includes
42
+********************************************************************************/
43
+
44
+#include <avr/io.h>
45
+#include <avr/interrupt.h>
46
+
47
+#include "usiTwiSlave.h"
48
+//#include "../common/util.h"
49
+
50
+
51
+/********************************************************************************
52
+                            device dependent defines
53
+********************************************************************************/
54
+
55
+#if defined( __AVR_ATtiny167__ )
56
+#  define DDR_USI             DDRB
57
+#  define PORT_USI            PORTB
58
+#  define PIN_USI             PINB
59
+#  define PORT_USI_SDA        PB0
60
+#  define PORT_USI_SCL        PB2
61
+#  define PIN_USI_SDA         PINB0
62
+#  define PIN_USI_SCL         PINB2
63
+#  define USI_START_COND_INT  USISIF
64
+#  define USI_START_VECTOR    USI_START_vect
65
+#  define USI_OVERFLOW_VECTOR USI_OVERFLOW_vect
66
+#endif
67
+
68
+#if defined( __AVR_ATtiny2313__ )
69
+#  define DDR_USI             DDRB
70
+#  define PORT_USI            PORTB
71
+#  define PIN_USI             PINB
72
+#  define PORT_USI_SDA        PB5
73
+#  define PORT_USI_SCL        PB7
74
+#  define PIN_USI_SDA         PINB5
75
+#  define PIN_USI_SCL         PINB7
76
+#  define USI_START_COND_INT  USISIF
77
+#  define USI_START_VECTOR    USI_START_vect
78
+#  define USI_OVERFLOW_VECTOR USI_OVERFLOW_vect
79
+#endif
80
+
81
+#if defined(__AVR_ATtiny84__) | \
82
+     defined(__AVR_ATtiny44__)
83
+#  define DDR_USI             DDRA
84
+#  define PORT_USI            PORTA
85
+#  define PIN_USI             PINA
86
+#  define PORT_USI_SDA        PORTA6
87
+#  define PORT_USI_SCL        PORTA4
88
+#  define PIN_USI_SDA         PINA6
89
+#  define PIN_USI_SCL         PINA4
90
+#  define USI_START_COND_INT  USISIF
91
+#  define USI_START_VECTOR    USI_START_vect
92
+#  define USI_OVERFLOW_VECTOR USI_OVF_vect
93
+#endif
94
+
95
+#if defined( __AVR_ATtiny25__ ) | \
96
+     defined( __AVR_ATtiny45__ ) | \
97
+     defined( __AVR_ATtiny85__ )
98
+#  define DDR_USI             DDRB
99
+#  define PORT_USI            PORTB
100
+#  define PIN_USI             PINB
101
+#  define PORT_USI_SDA        PB0
102
+#  define PORT_USI_SCL        PB2
103
+#  define PIN_USI_SDA         PINB0
104
+#  define PIN_USI_SCL         PINB2
105
+#  define USI_START_COND_INT  USISIF
106
+#  define USI_START_VECTOR    USI_START_vect
107
+#  define USI_OVERFLOW_VECTOR USI_OVF_vect
108
+#endif
109
+
110
+#if defined( __AVR_ATtiny26__ )
111
+#  define DDR_USI             DDRB
112
+#  define PORT_USI            PORTB
113
+#  define PIN_USI             PINB
114
+#  define PORT_USI_SDA        PB0
115
+#  define PORT_USI_SCL        PB2
116
+#  define PIN_USI_SDA         PINB0
117
+#  define PIN_USI_SCL         PINB2
118
+#  define USI_START_COND_INT  USISIF
119
+#  define USI_START_VECTOR    USI_STRT_vect
120
+#  define USI_OVERFLOW_VECTOR USI_OVF_vect
121
+#endif
122
+
123
+#if defined( __AVR_ATtiny261__ ) | \
124
+      defined( __AVR_ATtiny461__ ) | \
125
+      defined( __AVR_ATtiny861__ )
126
+#  define DDR_USI             DDRB
127
+#  define PORT_USI            PORTB
128
+#  define PIN_USI             PINB
129
+#  define PORT_USI_SDA        PB0
130
+#  define PORT_USI_SCL        PB2
131
+#  define PIN_USI_SDA         PINB0
132
+#  define PIN_USI_SCL         PINB2
133
+#  define USI_START_COND_INT  USISIF
134
+#  define USI_START_VECTOR    USI_START_vect
135
+#  define USI_OVERFLOW_VECTOR USI_OVF_vect
136
+#endif
137
+
138
+#if defined( __AVR_ATmega165__ ) | \
139
+     defined( __AVR_ATmega325__ ) | \
140
+     defined( __AVR_ATmega3250__ ) | \
141
+     defined( __AVR_ATmega645__ ) | \
142
+     defined( __AVR_ATmega6450__ ) | \
143
+     defined( __AVR_ATmega329__ ) | \
144
+     defined( __AVR_ATmega3290__ )
145
+#  define DDR_USI             DDRE
146
+#  define PORT_USI            PORTE
147
+#  define PIN_USI             PINE
148
+#  define PORT_USI_SDA        PE5
149
+#  define PORT_USI_SCL        PE4
150
+#  define PIN_USI_SDA         PINE5
151
+#  define PIN_USI_SCL         PINE4
152
+#  define USI_START_COND_INT  USISIF
153
+#  define USI_START_VECTOR    USI_START_vect
154
+#  define USI_OVERFLOW_VECTOR USI_OVERFLOW_vect
155
+#endif
156
+
157
+#if defined( __AVR_ATmega169__ )
158
+#  define DDR_USI             DDRE
159
+#  define PORT_USI            PORTE
160
+#  define PIN_USI             PINE
161
+#  define PORT_USI_SDA        PE5
162
+#  define PORT_USI_SCL        PE4
163
+#  define PIN_USI_SDA         PINE5
164
+#  define PIN_USI_SCL         PINE4
165
+#  define USI_START_COND_INT  USISIF
166
+#  define USI_START_VECTOR    USI_START_vect
167
+#  define USI_OVERFLOW_VECTOR USI_OVERFLOW_vect
168
+#endif
169
+
170
+
171
+
172
+/********************************************************************************
173
+
174
+                        functions implemented as macros
175
+
176
+********************************************************************************/
177
+
178
+#define SET_USI_TO_SEND_ACK( ) \
179
+{ \
180
+  /* prepare ACK */ \
181
+  USIDR = 0; \
182
+  /* set SDA as output */ \
183
+  DDR_USI |= ( 1 << PORT_USI_SDA ); \
184
+  /* clear all interrupt flags, except Start Cond */ \
185
+  USISR = \
186
+       ( 0 << USI_START_COND_INT ) | \
187
+       ( 1 << USIOIF ) | ( 1 << USIPF ) | \
188
+       ( 1 << USIDC )| \
189
+       /* set USI counter to shift 1 bit */ \
190
+       ( 0x0E << USICNT0 ); \
191
+}
192
+
193
+#define SET_USI_TO_READ_ACK( ) \
194
+{ \
195
+  /* set SDA as input */ \
196
+  DDR_USI &= ~( 1 << PORT_USI_SDA ); \
197
+  /* prepare ACK */ \
198
+  USIDR = 0; \
199
+  /* clear all interrupt flags, except Start Cond */ \
200
+  USISR = \
201
+       ( 0 << USI_START_COND_INT ) | \
202
+       ( 1 << USIOIF ) | \
203
+       ( 1 << USIPF ) | \
204
+       ( 1 << USIDC ) | \
205
+       /* set USI counter to shift 1 bit */ \
206
+       ( 0x0E << USICNT0 ); \
207
+}
208
+
209
+#define SET_USI_TO_TWI_START_CONDITION_MODE( ) \
210
+{ \
211
+  USICR = \
212
+       /* enable Start Condition Interrupt, disable Overflow Interrupt */ \
213
+       ( 1 << USISIE ) | ( 0 << USIOIE ) | \
214
+       /* set USI in Two-wire mode, no USI Counter overflow hold */ \
215
+       ( 1 << USIWM1 ) | ( 0 << USIWM0 ) | \
216
+       /* Shift Register Clock Source = External, positive edge */ \
217
+       /* 4-Bit Counter Source = external, both edges */ \
218
+       ( 1 << USICS1 ) | ( 0 << USICS0 ) | ( 0 << USICLK ) | \
219
+       /* no toggle clock-port pin */ \
220
+       ( 0 << USITC ); \
221
+  USISR = \
222
+        /* clear all interrupt flags, except Start Cond */ \
223
+        ( 0 << USI_START_COND_INT ) | ( 1 << USIOIF ) | ( 1 << USIPF ) | \
224
+        ( 1 << USIDC ) | ( 0x0 << USICNT0 ); \
225
+}
226
+
227
+#define SET_USI_TO_SEND_DATA( ) \
228
+{ \
229
+  /* set SDA as output */ \
230
+  DDR_USI |=  ( 1 << PORT_USI_SDA ); \
231
+  /* clear all interrupt flags, except Start Cond */ \
232
+  USISR    =  \
233
+       ( 0 << USI_START_COND_INT ) | ( 1 << USIOIF ) | ( 1 << USIPF ) | \
234
+       ( 1 << USIDC) | \
235
+       /* set USI to shift out 8 bits */ \
236
+       ( 0x0 << USICNT0 ); \
237
+}
238
+
239
+#define SET_USI_TO_READ_DATA( ) \
240
+{ \
241
+  /* set SDA as input */ \
242
+  DDR_USI &= ~( 1 << PORT_USI_SDA ); \
243
+  /* clear all interrupt flags, except Start Cond */ \
244
+  USISR    = \
245
+       ( 0 << USI_START_COND_INT ) | ( 1 << USIOIF ) | \
246
+       ( 1 << USIPF ) | ( 1 << USIDC ) | \
247
+       /* set USI to shift out 8 bits */ \
248
+       ( 0x0 << USICNT0 ); \
249
+}
250
+
251
+#define USI_RECEIVE_CALLBACK() \
252
+{ \
253
+    if (usi_onReceiverPtr) \
254
+    { \
255
+        if (usiTwiAmountDataInReceiveBuffer()) \
256
+        { \
257
+            usi_onReceiverPtr(usiTwiAmountDataInReceiveBuffer()); \
258
+        } \
259
+    } \
260
+}
261
+
262
+#define ONSTOP_USI_RECEIVE_CALLBACK() \
263
+{ \
264
+    if (USISR & ( 1 << USIPF )) \
265
+    { \
266
+        USI_RECEIVE_CALLBACK(); \
267
+    } \
268
+}
269
+
270
+
271
+#define USI_REQUEST_CALLBACK() \
272
+{ \
273
+    USI_RECEIVE_CALLBACK(); \
274
+    if(usi_onRequestPtr) usi_onRequestPtr(); \
275
+}
276
+
277
+/********************************************************************************
278
+
279
+                                   typedef's
280
+
281
+********************************************************************************/
282
+
283
+typedef enum
284
+{
285
+  USI_SLAVE_CHECK_ADDRESS                = 0x00,
286
+  USI_SLAVE_SEND_DATA                    = 0x01,
287
+  USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA = 0x02,
288
+  USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA   = 0x03,
289
+  USI_SLAVE_REQUEST_DATA                 = 0x04,
290
+  USI_SLAVE_GET_DATA_AND_SEND_ACK        = 0x05
291
+} overflowState_t;
292
+
293
+
294
+
295
+/********************************************************************************
296
+
297
+                                local variables
298
+
299
+********************************************************************************/
300
+
301
+static uint8_t                  slaveAddress;
302
+static volatile overflowState_t overflowState;
303
+
304
+
305
+static uint8_t          rxBuf[ TWI_RX_BUFFER_SIZE ];
306
+static volatile uint8_t rxHead;
307
+static volatile uint8_t rxTail;
308
+static volatile uint8_t rxCount;
309
+
310
+static uint8_t          txBuf[ TWI_TX_BUFFER_SIZE ];
311
+static volatile uint8_t txHead;
312
+static volatile uint8_t txTail;
313
+static volatile uint8_t txCount;
314
+
315
+
316
+
317
+/********************************************************************************
318
+
319
+                                local functions
320
+
321
+********************************************************************************/
322
+
323
+
324
+
325
+// flushes the TWI buffers
326
+
327
+static
328
+void
329
+flushTwiBuffers(
330
+  void
331
+)
332
+{
333
+  rxTail = 0;
334
+  rxHead = 0;
335
+  rxCount = 0;
336
+  txTail = 0;
337
+  txHead = 0;
338
+  txCount = 0;
339
+} // end flushTwiBuffers
340
+
341
+
342
+
343
+/********************************************************************************
344
+
345
+                                public functions
346
+
347
+********************************************************************************/
348
+
349
+
350
+
351
+// initialise USI for TWI slave mode
352
+
353
+void
354
+usiTwiSlaveInit(
355
+  uint8_t ownAddress
356
+)
357
+{
358
+
359
+  flushTwiBuffers( );
360
+
361
+  slaveAddress = ownAddress;
362
+
363
+  // In Two Wire mode (USIWM1, USIWM0 = 1X), the slave USI will pull SCL
364
+  // low when a start condition is detected or a counter overflow (only
365
+  // for USIWM1, USIWM0 = 11).  This inserts a wait state.  SCL is released
366
+  // by the ISRs (USI_START_vect and USI_OVERFLOW_vect).
367
+
368
+  // Set SCL and SDA as output
369
+  DDR_USI |= ( 1 << PORT_USI_SCL ) | ( 1 << PORT_USI_SDA );
370
+
371
+  // set SCL high
372
+  PORT_USI |= ( 1 << PORT_USI_SCL );
373
+
374
+  // set SDA high
375
+  PORT_USI |= ( 1 << PORT_USI_SDA );
376
+
377
+  // Set SDA as input
378
+  DDR_USI &= ~( 1 << PORT_USI_SDA );
379
+
380
+  USICR =
381
+       // enable Start Condition Interrupt
382
+       ( 1 << USISIE ) |
383
+       // disable Overflow Interrupt
384
+       ( 0 << USIOIE ) |
385
+       // set USI in Two-wire mode, no USI Counter overflow hold
386
+       ( 1 << USIWM1 ) | ( 0 << USIWM0 ) |
387
+       // Shift Register Clock Source = external, positive edge
388
+       // 4-Bit Counter Source = external, both edges
389
+       ( 1 << USICS1 ) | ( 0 << USICS0 ) | ( 0 << USICLK ) |
390
+       // no toggle clock-port pin
391
+       ( 0 << USITC );
392
+
393
+  // clear all interrupt flags and reset overflow counter
394
+
395
+  USISR = ( 1 << USI_START_COND_INT ) | ( 1 << USIOIF ) | ( 1 << USIPF ) | ( 1 << USIDC );
396
+
397
+} // end usiTwiSlaveInit
398
+
399
+
400
+bool usiTwiDataInTransmitBuffer(void)
401
+{
402
+
403
+  // return 0 (false) if the receive buffer is empty
404
+  return txCount;
405
+
406
+} // end usiTwiDataInTransmitBuffer
407
+
408
+
409
+// put data in the transmission buffer, wait if buffer is full
410
+
411
+void
412
+usiTwiTransmitByte(
413
+  uint8_t data
414
+)
415
+{
416
+
417
+  // kpl uint8_t tmphead;
418
+
419
+  // wait for free space in buffer
420
+  while ( txCount == TWI_TX_BUFFER_SIZE) ;
421
+
422
+  // store data in buffer
423
+  txBuf[ txHead ] = data;
424
+  txHead = ( txHead + 1 ) & TWI_TX_BUFFER_MASK;
425
+  txCount++;
426
+
427
+} // end usiTwiTransmitByte
428
+
429
+
430
+
431
+
432
+
433
+// return a byte from the receive buffer, wait if buffer is empty
434
+
435
+uint8_t
436
+usiTwiReceiveByte(
437
+  void
438
+)
439
+{
440
+  uint8_t rtn_byte;
441
+
442
+  // wait for Rx data
443
+  while ( !rxCount );
444
+
445
+  rtn_byte = rxBuf [ rxTail ];
446
+  // calculate buffer index
447
+  rxTail = ( rxTail + 1 ) & TWI_RX_BUFFER_MASK;
448
+  rxCount--;
449
+
450
+  // return data from the buffer.
451
+  return rtn_byte;
452
+
453
+} // end usiTwiReceiveByte
454
+
455
+
456
+
457
+uint8_t usiTwiAmountDataInReceiveBuffer(void)
458
+{
459
+    return rxCount;
460
+}
461
+
462
+
463
+
464
+
465
+/********************************************************************************
466
+
467
+                            USI Start Condition ISR
468
+
469
+********************************************************************************/
470
+
471
+ISR( USI_START_VECTOR )
472
+{
473
+
474
+  /*
475
+  // This triggers on second write, but claims to the callback there is only *one* byte in buffer
476
+  ONSTOP_USI_RECEIVE_CALLBACK();
477
+  */
478
+  /*
479
+  // This triggers on second write, but claims to the callback there is only *one* byte in buffer
480
+  USI_RECEIVE_CALLBACK();
481
+  */
482
+
483
+
484
+  // set default starting conditions for new TWI package
485
+  overflowState = USI_SLAVE_CHECK_ADDRESS;
486
+
487
+  // set SDA as input
488
+  DDR_USI &= ~( 1 << PORT_USI_SDA );
489
+
490
+  // wait for SCL to go low to ensure the Start Condition has completed (the
491
+  // start detector will hold SCL low ) - if a Stop Condition arises then leave
492
+  // the interrupt to prevent waiting forever - don't use USISR to test for Stop
493
+  // Condition as in Application Note AVR312 because the Stop Condition Flag is
494
+  // going to be set from the last TWI sequence
495
+  while (
496
+       // SCL his high
497
+       ( PIN_USI & ( 1 << PIN_USI_SCL ) ) &&
498
+       // and SDA is low
499
+       !( ( PIN_USI & ( 1 << PIN_USI_SDA ) ) )
500
+  );
501
+
502
+
503
+  if ( !( PIN_USI & ( 1 << PIN_USI_SDA ) ) )
504
+  {
505
+
506
+    // a Stop Condition did not occur
507
+
508
+    USICR =
509
+         // keep Start Condition Interrupt enabled to detect RESTART
510
+         ( 1 << USISIE ) |
511
+         // enable Overflow Interrupt
512
+         ( 1 << USIOIE ) |
513
+         // set USI in Two-wire mode, hold SCL low on USI Counter overflow
514
+         ( 1 << USIWM1 ) | ( 1 << USIWM0 ) |
515
+         // Shift Register Clock Source = External, positive edge
516
+         // 4-Bit Counter Source = external, both edges
517
+         ( 1 << USICS1 ) | ( 0 << USICS0 ) | ( 0 << USICLK ) |
518
+         // no toggle clock-port pin
519
+         ( 0 << USITC );
520
+
521
+  }
522
+  else
523
+  {
524
+    // a Stop Condition did occur
525
+
526
+    USICR =
527
+         // enable Start Condition Interrupt
528
+         ( 1 << USISIE ) |
529
+         // disable Overflow Interrupt
530
+         ( 0 << USIOIE ) |
531
+         // set USI in Two-wire mode, no USI Counter overflow hold
532
+         ( 1 << USIWM1 ) | ( 0 << USIWM0 ) |
533
+         // Shift Register Clock Source = external, positive edge
534
+         // 4-Bit Counter Source = external, both edges
535
+         ( 1 << USICS1 ) | ( 0 << USICS0 ) | ( 0 << USICLK ) |
536
+         // no toggle clock-port pin
537
+         ( 0 << USITC );
538
+
539
+  } // end if
540
+
541
+  USISR =
542
+       // clear interrupt flags - resetting the Start Condition Flag will
543
+       // release SCL
544
+       ( 1 << USI_START_COND_INT ) | ( 1 << USIOIF ) |
545
+       ( 1 << USIPF ) |( 1 << USIDC ) |
546
+       // set USI to sample 8 bits (count 16 external SCL pin toggles)
547
+       ( 0x0 << USICNT0);
548
+
549
+
550
+} // end ISR( USI_START_VECTOR )
551
+
552
+
553
+
554
+/********************************************************************************
555
+
556
+                                USI Overflow ISR
557
+
558
+Handles all the communication.
559
+
560
+Only disabled when waiting for a new Start Condition.
561
+
562
+********************************************************************************/
563
+
564
+ISR( USI_OVERFLOW_VECTOR )
565
+{
566
+
567
+  switch ( overflowState )
568
+  {
569
+
570
+    // Address mode: check address and send ACK (and next USI_SLAVE_SEND_DATA) if OK,
571
+    // else reset USI
572
+    case USI_SLAVE_CHECK_ADDRESS:
573
+      if ( ( USIDR == 0 ) || ( ( USIDR >> 1 ) == slaveAddress) )
574
+      {
575
+        if ( USIDR & 0x01 )
576
+        {
577
+          USI_REQUEST_CALLBACK();
578
+          overflowState = USI_SLAVE_SEND_DATA;
579
+        }
580
+        else
581
+        {
582
+          overflowState = USI_SLAVE_REQUEST_DATA;
583
+        } // end if
584
+        SET_USI_TO_SEND_ACK( );
585
+      }
586
+      else
587
+      {
588
+        SET_USI_TO_TWI_START_CONDITION_MODE( );
589
+      }
590
+      break;
591
+
592
+    // Master write data mode: check reply and goto USI_SLAVE_SEND_DATA if OK,
593
+    // else reset USI
594
+    case USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA:
595
+      if ( USIDR )
596
+      {
597
+        // if NACK, the master does not want more data
598
+        SET_USI_TO_TWI_START_CONDITION_MODE( );
599
+        return;
600
+      }
601
+      // from here we just drop straight into USI_SLAVE_SEND_DATA if the
602
+      // master sent an ACK
603
+
604
+    // copy data from buffer to USIDR and set USI to shift byte
605
+    // next USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA
606
+    case USI_SLAVE_SEND_DATA:
607
+      // Get data from Buffer
608
+      if ( txCount )
609
+      {
610
+        USIDR = txBuf[ txTail ];
611
+        txTail = ( txTail + 1 ) & TWI_TX_BUFFER_MASK;
612
+        txCount--;
613
+      }
614
+      else
615
+      {
616
+        // the buffer is empty
617
+        SET_USI_TO_READ_ACK( ); // This might be neccessary sometimes see http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=805227#805227
618
+        SET_USI_TO_TWI_START_CONDITION_MODE( );
619
+        return;
620
+      } // end if
621
+      overflowState = USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA;
622
+      SET_USI_TO_SEND_DATA( );
623
+      break;
624
+
625
+    // set USI to sample reply from master
626
+    // next USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA
627
+    case USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA:
628
+      overflowState = USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA;
629
+      SET_USI_TO_READ_ACK( );
630
+      break;
631
+
632
+    // Master read data mode: set USI to sample data from master, next
633
+    // USI_SLAVE_GET_DATA_AND_SEND_ACK
634
+    case USI_SLAVE_REQUEST_DATA:
635
+      overflowState = USI_SLAVE_GET_DATA_AND_SEND_ACK;
636
+      SET_USI_TO_READ_DATA( );
637
+      break;
638
+
639
+    // copy data from USIDR and send ACK
640
+    // next USI_SLAVE_REQUEST_DATA
641
+    case USI_SLAVE_GET_DATA_AND_SEND_ACK:
642
+      // put data into buffer
643
+      // check buffer size
644
+      if ( rxCount < TWI_RX_BUFFER_SIZE )
645
+      {
646
+        rxBuf[ rxHead ] = USIDR;
647
+        rxHead = ( rxHead + 1 ) & TWI_RX_BUFFER_MASK;
648
+        rxCount++;
649
+      } else {
650
+        // overrun
651
+        // drop data
652
+      }
653
+      // next USI_SLAVE_REQUEST_DATA
654
+      overflowState = USI_SLAVE_REQUEST_DATA;
655
+      SET_USI_TO_SEND_ACK( );
656
+      break;
657
+
658
+  } // end switch
659
+
660
+} // end ISR( USI_OVERFLOW_VECTOR )

+ 97
- 0
control/tiny/usiTwiSlave.h 파일 보기

@@ -0,0 +1,97 @@
1
+/********************************************************************************
2
+
3
+Header file for the USI TWI Slave driver.
4
+
5
+Created by Donald R. Blake
6
+donblake at worldnet.att.net
7
+
8
+---------------------------------------------------------------------------------
9
+
10
+Created from Atmel source files for Application Note AVR312: Using the USI Module
11
+as an I2C slave.
12
+
13
+This program is free software; you can redistribute it and/or modify it under the
14
+terms of the GNU General Public License as published by the Free Software
15
+Foundation; either version 2 of the License, or (at your option) any later
16
+version.
17
+
18
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
19
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
20
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
21
+
22
+---------------------------------------------------------------------------------
23
+
24
+Change Activity:
25
+
26
+    Date       Description
27
+   ------      -------------
28
+  15 Mar 2007  Created.
29
+
30
+********************************************************************************/
31
+
32
+
33
+
34
+#ifndef _USI_TWI_SLAVE_H_
35
+#define _USI_TWI_SLAVE_H_
36
+
37
+
38
+
39
+/********************************************************************************
40
+
41
+                                    includes
42
+
43
+********************************************************************************/
44
+
45
+#include <stdbool.h>
46
+
47
+
48
+
49
+/********************************************************************************
50
+
51
+                                   prototypes
52
+
53
+********************************************************************************/
54
+
55
+void    usiTwiSlaveInit( uint8_t );
56
+void    usiTwiTransmitByte( uint8_t );
57
+uint8_t usiTwiReceiveByte( void );
58
+bool    usiTwiDataInReceiveBuffer( void );
59
+void    (*_onTwiDataRequest)(void);
60
+bool    usiTwiDataInTransmitBuffer(void);
61
+uint8_t usiTwiAmountDataInReceiveBuffer(void);
62
+// on_XXX handler pointers
63
+void    (*usi_onRequestPtr)(void);
64
+void    (*usi_onReceiverPtr)(uint8_t);
65
+
66
+
67
+/********************************************************************************
68
+
69
+                           driver buffer definitions
70
+
71
+********************************************************************************/
72
+
73
+// permitted RX buffer sizes: 1, 2, 4, 8, 16, 32, 64, 128 or 256
74
+
75
+#ifndef TWI_RX_BUFFER_SIZE
76
+#define TWI_RX_BUFFER_SIZE  ( 16 )
77
+#endif
78
+#define TWI_RX_BUFFER_MASK  ( TWI_RX_BUFFER_SIZE - 1 )
79
+
80
+#if ( TWI_RX_BUFFER_SIZE & TWI_RX_BUFFER_MASK )
81
+#  error TWI RX buffer size is not a power of 2
82
+#endif
83
+
84
+// permitted TX buffer sizes: 1, 2, 4, 8, 16, 32, 64, 128 or 256
85
+
86
+#ifndef TWI_TX_BUFFER_SIZE
87
+#define TWI_TX_BUFFER_SIZE ( 16 )
88
+#endif
89
+#define TWI_TX_BUFFER_MASK ( TWI_TX_BUFFER_SIZE - 1 )
90
+
91
+#if ( TWI_TX_BUFFER_SIZE & TWI_TX_BUFFER_MASK )
92
+#  error TWI TX buffer size is not a power of 2
93
+#endif
94
+
95
+
96
+
97
+#endif  // ifndef _USI_TWI_SLAVE_H_

Loading…
취소
저장