Przeglądaj źródła

Initial working version of long interval timer and PWM under the control of picadae_cmd.py.

master
kevin.larke 4 lat temu
rodzic
commit
61758bb9de
2 zmienionych plików z 136 dodań i 22 usunięć
  1. 83
    11
      control/app/picadae_cmd.py
  2. 53
    11
      control/tiny/i2c_timer_pwm.c

+ 83
- 11
control/app/picadae_cmd.py Wyświetl plik

@@ -120,10 +120,14 @@ class App:
120 120
                 print("in:",msg[1])
121 121
 
122 122
 
123
-    def _parse_error( self, msg ):
123
+    def _parse_error( self, msg, cmd_str=None ):
124
+
125
+        if cmd_str:
126
+            msg += " Command:{}".format(cmd_str)
127
+            
124 128
         return (None,msg)
125 129
 
126
-    def _parse_int( self, token, var_label, max_value ):
130
+    def _parse_int( self, token, var_label, min_value, max_value ):
127 131
         # convert the i2c destination address to an integer
128 132
         try:
129 133
             int_value = int(token)
@@ -131,11 +135,75 @@ class App:
131 135
             return self._parse_error("Synax error: '{}' is not a legal integer.".format(token))
132 136
 
133 137
         # validate the i2c address value
134
-        if 0 > int_value or int_value > max_value:
138
+        if min_value > int_value or int_value > max_value:
135 139
             return self._parse_error("Syntax error: '{}' {} out of range 0 to {}.".format(token,int_value,max_value))
136 140
 
137 141
         return (int_value,None)
138 142
     
143
+    def parse_app_cmd( self, cmd_str ):
144
+        """
145
+        Command syntax <opcode> <remote_i2c_addr> <value>
146
+        """
147
+        
148
+        op_tok_idx  = 0
149
+        i2c_tok_idx = 1
150
+        val_tok_idx = 2
151
+        
152
+        cmdD = {
153
+            'p':{ 'reg':0, 'n':1, 'min':0, 'max':4 },       # timer pre-scalar: sets timer tick rate
154
+            't':{ 'reg':1, 'n':2, 'min':0, 'max':10e7 },    # microseconds
155
+            'd':{ 'reg':3, 'n':1, 'min':0, 'max':100 },    # pwm duty cylce (0-100%)
156
+            'f':{ 'reg':4, 'n':1, 'min':1, 'max':5 },       # pwm frequency divider 1=1,2=8,3=64,4=256,5=1024
157
+            }
158
+
159
+        cmd_str = cmd_str.strip()
160
+
161
+        tokenL = cmd_str.split(' ')
162
+
163
+        # validate the counf of tokens
164
+        if len(tokenL) != 3:
165
+            return self._parse_error("Syntax error: Invalid token count.",cmd_str)
166
+
167
+        opcode = tokenL[op_tok_idx]
168
+        
169
+        # validate the opcode
170
+        if opcode not in cmdD:
171
+            return self._parse_error("Syntax error: Invalid opcode.",cmd_str)
172
+
173
+        # convert the i2c destination address to an integer
174
+        i2c_addr, msg = self._parse_int( tokenL[i2c_tok_idx], "i2c address", 0,127 )
175
+
176
+        if i2c_addr is None:
177
+            return (None,msg)
178
+
179
+        d = cmdD[ opcode ]
180
+        
181
+        # get the value
182
+        value, msg = self._parse_int( tokenL[val_tok_idx], "command value", d['min'], d['max'] )
183
+
184
+        if value is None:
185
+            return (value,msg)
186
+
187
+        dataL = [ value ]
188
+
189
+        if opcode == 't':
190
+            
191
+            coarse = int(value/(32*254))
192
+            fine   = int((value - coarse*32*254)/32)
193
+            dataL  = [ coarse, fine ]
194
+
195
+        elif opcode == 'd':
196
+            dataL = [ int(value * 255 / 100.0) ]
197
+
198
+        cmd_bV = bytearray( [ ord('w'), i2c_addr, d['reg'], len(dataL) ] + dataL )
199
+
200
+        if False:
201
+            print('cmd_bV:')
202
+            for x in cmd_bV:
203
+                print(int(x))
204
+
205
+        return (cmd_bV,None)
206
+    
139 207
     def parse_cmd( self, cmd_str ):
140 208
 
141 209
         op_tok_idx  = 0
@@ -143,7 +211,11 @@ class App:
143 211
         reg_tok_idx = 2
144 212
         rdn_tok_idx = 3
145 213
         
146
-        cmd_str.strip()
214
+        cmd_str = cmd_str.strip()
215
+
216
+        # if this is a high level command
217
+        if cmd_str[0] not in ['r','w']:
218
+            return self.parse_app_cmd( cmd_str )
147 219
 
148 220
         # convert the command string to tokens
149 221
         tokenL = cmd_str.split(' ')
@@ -163,16 +235,16 @@ class App:
163 235
         if op_code == 'r' and len(tokenL) != 4:
164 236
             return self._parse_error("Syntax error: Illegal read syntax.")
165 237
 
166
-        if op_code == 'w' and len(tokenL) == 4:
238
+        if op_code == 'w' and len(tokenL) < 4:
167 239
             return self._parse_error("Syntax error: Illegal write command too short.")
168 240
 
169 241
         # convert the i2c destination address to an integer
170
-        i2c_addr, msg = self._parse_int( tokenL[i2c_tok_idx], "i2c address", 127 )
242
+        i2c_addr, msg = self._parse_int( tokenL[i2c_tok_idx], "i2c address", 0,127 )
171 243
 
172 244
         if i2c_addr is None:
173 245
             return (None,msg)
174 246
 
175
-        reg_addr, msg = self._parse_int( tokenL[reg_tok_idx], "reg address", 255 )
247
+        reg_addr, msg = self._parse_int( tokenL[reg_tok_idx], "reg address", 0, 255 )
176 248
 
177 249
         if reg_addr is None:
178 250
             return (None,msg)
@@ -181,7 +253,7 @@ class App:
181 253
 
182 254
         # parse and validate the count of bytes to read
183 255
         if op_code == 'r':
184
-            op_byteN, msg = self._parse_int( tokenL[ rdn_tok_idx ], "read byte count", 255 )
256
+            op_byteN, msg = self._parse_int( tokenL[ rdn_tok_idx ], "read byte count", 0, 255 )
185 257
 
186 258
             if op_byteN is None:
187 259
                 return (None,msg)
@@ -191,7 +263,7 @@ class App:
191 263
         elif op_code == 'w':
192 264
 
193 265
             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 )
266
+                value, msg = self._parse_int( tokenL[i], "write value: %i" % (j), 0, 255 )
195 267
                 
196 268
                 if value is None:
197 269
                     return (None,msg)
@@ -238,7 +310,7 @@ class App:
238 310
 
239 311
                 # if a serial msg was received
240 312
                 if msg is not None and msg[0] == DATA_MSG:
241
-                    print("ser:",msg[1])
313
+                    print("ser:",msg[1],int(msg[1][0]))
242 314
             
243 315
             
244 316
         self.serialProc.quit()
@@ -252,7 +324,7 @@ def parse_args():
252 324
     ap = argparse.ArgumentParser(description=descStr)
253 325
 
254 326
 
255
-    ap.add_argument("-s","--setup",                     default="cfg/p_ac.yml",  help="YAML configuration file.")
327
+    ap.add_argument("-s","--setup",                     default="picadae_cmd.yml",  help="YAML configuration file.")
256 328
     ap.add_argument("-c","--cmd",   nargs="*",                                   help="Give a command as multiple tokens")
257 329
     ap.add_argument("-r","--run",                                                help="Run a named command list from the setup file.")
258 330
     ap.add_argument("-l","--log_level",choices=logL,     default="warning",      help="Set logging level: debug,info,warning,error,critical. Default:warning")

+ 53
- 11
control/tiny/i2c_timer_pwm.c Wyświetl plik

@@ -12,8 +12,8 @@
12 12
 
13 13
 enum
14 14
 {
15
- kCS13_10_idx     = 0,  // Timer 1 Prescalar (CS13,CS12,CS11,CS10) from Table 12-5 pg 89
16
- kTmr0_Coarse_idx = 1,  // count of times timer0 count to 255 before OCR1C is set to Tmr0_Minor
15
+ 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
16
+ kTmr0_Coarse_idx = 1,  // count of times timer0 count to 255 before OCR1C is set to Tmr0_Fine
17 17
  kTmr0_Fine_idx   = 2,  // OCR1C timer match value
18 18
  kPWM_Duty_idx    = 3,  //
19 19
  kPWM_Freq_idx    = 4,  // 1-4 = clock divider=1=1,2=8,3=64,4=256,5=1024
@@ -21,9 +21,9 @@ enum
21 21
 
22 22
 volatile uint8_t ctl_regs[] =
23 23
 {
24
- 0x0f,   // 0 (0-15)  timer prescalar 0=stop, 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
25
- 0,      // 1 (0-255) Tmr0_Coarse count of times timer count to 255 before loading Tmr0_Minor for final count.
26
- 244,    // 2 (0-254) Tmr0_Fine OCR1C value on final phase before triggering timer
24
+   9,    // 0  9=32 us period w/ 8Mhz clock (timer tick rate) 
25
+ 123,    // 1 (0-255) Tmr0_Coarse count of times timer count to 255 before loading Tmr0_Minor for final count.
26
+   8,    // 2 (0-254) Tmr0_Fine OCR1C value on final phase before triggering timer
27 27
  127,    // 3 (0-255) Duty cycle
28 28
  4,      // 4 (1-4)   PWM Frequency (clock pre-scaler) 
29 29
 };
@@ -32,9 +32,47 @@ volatile uint8_t ctl_regs[] =
32 32
 volatile uint8_t reg_position = 0;
33 33
 const uint8_t reg_size = sizeof(ctl_regs);
34 34
 
35
+volatile uint8_t tmr_state        = 0;    
36
+volatile uint8_t tmr_coarse_cur   = 0;
37
+
38
+void tmr_reset()
39
+{
40
+  if( ctl_regs[kTmr0_Coarse_idx] > 0 )
41
+  {
42
+    tmr_state = 1;
43
+    OCR1C     = 254;
44
+  }
45
+  else
46
+  {
47
+    tmr_state = 2;
48
+    OCR1C     = ctl_regs[kTmr0_Fine_idx];
49
+  }
50
+  
51
+  tmr_coarse_cur = 0;  
52
+}
53
+
35 54
 ISR(TIMER1_OVF_vect)
36 55
 {
37
-  PINB = _BV(PINB4) + _BV(PINB1);  // writes to PINB toggle the pins
56
+  switch( tmr_state )
57
+  {
58
+    case 0:
59
+      break;
60
+      
61
+    case 1:
62
+      if( ++tmr_coarse_cur >= ctl_regs[kTmr0_Coarse_idx] )
63
+      {
64
+        tmr_state  = 2;
65
+        OCR1C     = ctl_regs[kTmr0_Fine_idx];        
66
+      }
67
+      break;
68
+      
69
+    case 2:
70
+      PINB = _BV(PINB4) + _BV(PINB1);  // writes to PINB toggle the pins
71
+
72
+      tmr_reset();
73
+      break;
74
+  }
75
+  
38 76
   
39 77
 }
40 78
 
@@ -46,8 +84,12 @@ void timer1_init()
46 84
   TCCR1  |= _BV(CTC1);      // Reset TCNT1 to 0 when TCNT1==OCR1C 
47 85
   TCCR1  |= _BV(PWM1A);     // Enable PWM A
48 86
   TCCR1  |= ctl_regs[kCS13_10_idx] & 0x0f;  // 
49
-  OCR1C   = ctl_regs[kTmr0_Fine_idx];
50
-  TIMSK  |= _BV(TOIE1);     // Enable interrupt TIMER1_OVF  
87
+  GTCCR  |= _BV(PSR1);      // Set the pre-scaler to the selected value
88
+
89
+  tmr_reset();
90
+  
91
+  TIMSK  |= _BV(TOIE1);     // Enable interrupt TIMER1_OVF
92
+  
51 93
 }
52 94
 
53 95
 void pwm0_update()
@@ -136,9 +178,9 @@ void on_receive( uint8_t byteN )
136 178
 
137 179
         if( kCS13_10_idx <= reg_position && reg_position <= kTmr0_Fine_idx )
138 180
           timer1_init();
139
-
140
-        if( kPWM_Duty_idx <= reg_position && reg_position <= kPWM_Freq_idx )
141
-          pwm0_update();
181
+        else
182
+          if( kPWM_Duty_idx <= reg_position && reg_position <= kPWM_Freq_idx )
183
+            pwm0_update();
142 184
 
143 185
         
144 186
         reg_position++;

Ładowanie…
Anuluj
Zapisz