回答編集履歴

2

サンプル追加

2021/01/31 13:23

投稿

thkana
thkana

スコア7703

test CHANGED
@@ -11,3 +11,391 @@
11
11
 
12
12
 
13
13
  (話だけでわかるか? とも思うけど、サンプルを書けとかいわれるとちょっと面倒だなぁ...)
14
+
15
+
16
+
17
+ ---
18
+
19
+
20
+
21
+ 面倒といいながら、SD書き込み中にちゃんと割り込みがかかるか等、色々と気になったので作ってみました。ただし、ターゲットはArduino m0/PROで、そのままDueに持っていけるかどうかは知りません。どちらもATMELのARMだし、m0の方が低クロック少メモリなので期待は出来ますが。
22
+
23
+
24
+
25
+ 動作チェックとして他のマイコンで2s/555μs/694μs(それぞれ設定値、パルス同士は同期をとっていません)のパルスを作ってそれを突っ込んで大体2.0002s/22b(555)~22d(557)/ 2b6(694)~2b7(695)ぐらいの値が出ているのでそこそこかと。
26
+
27
+
28
+
29
+ SDカードの書き出しは数字で打ちたかったのですが、2秒に確実に収まるとは言えない感じだったのでバイナリにしています。書き込み時間は200~500msぐらいでばらつきます。Dueの方がCPUが早いのでもしかしたら数字でも出せるかもしれませんが、SDのI/Fが律速しているのかも。
30
+
31
+
32
+
33
+ ```Arduino
34
+
35
+ //Items.h
36
+
37
+ #include <cstddef>
38
+
39
+ #include <SD.h>
40
+
41
+
42
+
43
+ class Items {
44
+
45
+ //バッファ管理変数
46
+
47
+ volatile unsigned short *buf[2];
48
+
49
+ //データインデックス管理
50
+
51
+ volatile size_t idx[2];
52
+
53
+ //データ最大数
54
+
55
+ size_t bufSize;
56
+
57
+ //周数
58
+
59
+ volatile unsigned int round;
60
+
61
+ //周の最初の立ち上がりエッジ保存
62
+
63
+ unsigned long t0[2];
64
+
65
+ //前回の立ち上がり時刻保存
66
+
67
+ volatile unsigned long tPrev[2];
68
+
69
+ //周の初回判定
70
+
71
+ bool start;
72
+
73
+
74
+
75
+ public:
76
+
77
+ Items(size_t );
78
+
79
+ //割り込みハンドラ本体
80
+
81
+ void handle();
82
+
83
+ //周送り処理
84
+
85
+ void turnRound();
86
+
87
+ //データ書き出し
88
+
89
+ void logWrite(File);
90
+
91
+ };
92
+
93
+ ```
94
+
95
+ ```Arduino
96
+
97
+ //Itmes.cpp
98
+
99
+ #include <Arduino.h>
100
+
101
+ #include <cstddef>
102
+
103
+ #include <SD.h>
104
+
105
+ #include "Items.h"
106
+
107
+
108
+
109
+ Items::Items(size_t sz) : bufSize(sz) {
110
+
111
+ start = false;
112
+
113
+ round = 0;
114
+
115
+ buf[0] = new unsigned short[bufSize];
116
+
117
+ buf[1] = new unsigned short[bufSize];
118
+
119
+ };
120
+
121
+
122
+
123
+ //割り込みハンドラ本体
124
+
125
+ void Items::handle() {
126
+
127
+ unsigned long tt = micros();//時刻取得
128
+
129
+ size_t rr = round % 2; //使用バッファブロック選択
130
+
131
+ if (!start) { //周の初回の処理
132
+
133
+ idx[rr] = 0;
134
+
135
+ t0[rr] = tt;
136
+
137
+ tPrev[rr] = tt;
138
+
139
+ start = true;
140
+
141
+ }
142
+
143
+ if (idx[rr] < bufSize) { //バッファに余裕あるなら
144
+
145
+ buf[rr][idx[rr]++] = tt - tPrev[rr]; //前回との差分値を保存
146
+
147
+ }
148
+
149
+ tPrev[rr] = tt;//今回値を保存(次回差分計算用)
150
+
151
+ }
152
+
153
+
154
+
155
+ //周送り
156
+
157
+ void Items::turnRound() {
158
+
159
+ round += 1;
160
+
161
+ start = false;
162
+
163
+ }
164
+
165
+
166
+
167
+ //データ書き出し
168
+
169
+ void Items::logWrite(File logFile) {
170
+
171
+ if (round > 0) {
172
+
173
+ size_t rr = (round - 1) % 2;
174
+
175
+ //前回の周の最初の立ち上がりエッジ時刻
176
+
177
+ unsigned long tmp = t0[rr];
178
+
179
+ logFile.write((uint8_t*)&tmp, sizeof(unsigned long));
180
+
181
+ //前回の周のデータ数
182
+
183
+ tmp = idx[rr];
184
+
185
+ logFile.write((uint8_t*)&tmp, sizeof(unsigned long));
186
+
187
+ //データ本体書き込み
188
+
189
+ for (unsigned int i = 0; i < idx[rr]; i++) {
190
+
191
+ unsigned short tmp;
192
+
193
+ tmp = buf[rr][i];
194
+
195
+ logFile.write((uint8_t*)&tmp, sizeof(unsigned short));
196
+
197
+ }
198
+
199
+ }
200
+
201
+ }
202
+
203
+ ```
204
+
205
+ ```Arduino
206
+
207
+ //main.ino
208
+
209
+ #include <SPI.h>
210
+
211
+ #include <SD.h>
212
+
213
+
214
+
215
+ #include "Items.h"
216
+
217
+
218
+
219
+ typedef const int Pin;
220
+
221
+ Pin PhA = 6;
222
+
223
+ Pin PhB = 4;//m0のD2は割り込みを受けないみたいなので変更
224
+
225
+ Pin PhZ = 5;
226
+
227
+
228
+
229
+ //Z相読み出しのレイテンシを見込んで少し余裕を持たせる
230
+
231
+ const int RATIOA = 2880 + 32;
232
+
233
+ const int RATIOB = 3600 + 32;
234
+
235
+
236
+
237
+ Items pha(RATIOA), phb(RATIOB);
238
+
239
+
240
+
241
+ volatile bool isSDtriggered = false;//カード書き込みトリガ
242
+
243
+
244
+
245
+ volatile unsigned int roundZ = 0;//回転回数
246
+
247
+ volatile unsigned long bufZ[2];//Z相時刻
248
+
249
+
250
+
251
+ File logFile;
252
+
253
+
254
+
255
+ //A相割り込みハンドラ
256
+
257
+ void handleA() {
258
+
259
+ pha.handle();
260
+
261
+ }
262
+
263
+
264
+
265
+ //B相割り込みハンドラ
266
+
267
+ void handleB() {
268
+
269
+ phb.handle();
270
+
271
+ }
272
+
273
+
274
+
275
+ //Z相割り込みハンドラ
276
+
277
+ void handleZ() {
278
+
279
+ if (isSDtriggered) {
280
+
281
+ return; //前の処理が終わっていない
282
+
283
+ }
284
+
285
+ bufZ[++roundZ % 2] = micros();//時刻記録
286
+
287
+ pha.turnRound();//A相次の周へ
288
+
289
+ phb.turnRound();//B相次の周へ
290
+
291
+ isSDtriggered = true;//一周回ったので記録開始(SD操作はmainコンテキストで)
292
+
293
+ }
294
+
295
+
296
+
297
+ void setup() {
298
+
299
+ Serial.begin(115200);
300
+
301
+ pinMode(PhA, INPUT);
302
+
303
+ pinMode(PhB, INPUT);
304
+
305
+ pinMode(PhZ, INPUT);
306
+
307
+ //各相割り込み設定
308
+
309
+ attachInterrupt(digitalPinToInterrupt(PhA), handleA, RISING);
310
+
311
+ attachInterrupt(digitalPinToInterrupt(PhB), handleB, RISING);
312
+
313
+ attachInterrupt(digitalPinToInterrupt(PhZ), handleZ, RISING);
314
+
315
+
316
+
317
+ if (!SD.begin(10)) {
318
+
319
+ Serial.println("SD initialization failed!");
320
+
321
+ while (1);//カード初期化失敗したら停止
322
+
323
+ }
324
+
325
+ Serial.println("SD initialization done.");
326
+
327
+ }
328
+
329
+
330
+
331
+ void loop() {
332
+
333
+ if (isSDtriggered) { //SD書き込みトリガ掛かっていたら書き込み
334
+
335
+ if ( roundZ > 1&& roundZ<11) { //1周目完=2周目~9周目完=10周目のときSD書き込み
336
+
337
+ char fname[128];//ファイル名生成
338
+
339
+
340
+
341
+ Serial.println("SD start");
342
+
343
+ sprintf(fname, "/enc/round%d.txt", roundZ - 1); //round周数.txt
344
+
345
+ Serial.println("File: " + String(fname));
346
+
347
+ logFile = SD.open(fname, FILE_WRITE & ~O_APPEND); //ファイル先頭から書き込み
348
+
349
+ if (!logFile) {
350
+
351
+ Serial.println("File open error.");
352
+
353
+ while (1); //ファイルオープン失敗したら停止
354
+
355
+ }
356
+
357
+ unsigned long tmp = roundZ - 1; //現在(収集中)の前の周(収集完了)のデータ
358
+
359
+ logFile.write((uint8_t*)&tmp, sizeof(unsigned long));
360
+
361
+ tmp = bufZ[(roundZ - 1) % 2];
362
+
363
+ logFile.write((uint8_t*)&tmp, sizeof(unsigned long));
364
+
365
+ pha.logWrite(logFile); //A相データ書き込み
366
+
367
+ phb.logWrite(logFile); //B相データ書き込み
368
+
369
+ logFile.close();
370
+
371
+ Serial.println("SD done");
372
+
373
+ }
374
+
375
+ isSDtriggered = false;
376
+
377
+ }
378
+
379
+ }
380
+
381
+ /*ファイルフォーマットは
382
+
383
+ * 4byte 周ナンバー
384
+
385
+ * 4byte Z相立ち上がり時刻(micros値)
386
+
387
+ * 4byte A相立ち上がり時刻(micros値)
388
+
389
+ * 4byte A相データ数
390
+
391
+ * 2byte x データ数 A相間隔データ
392
+
393
+ * 4byte B相立ち上がり時刻(micros値)
394
+
395
+ * 4byte B相データ数
396
+
397
+ * 2byte x データ数 B相間隔データ
398
+
399
+ */
400
+
401
+ ```

1

表記変更

2021/01/31 13:23

投稿

thkana
thkana

スコア7703

test CHANGED
@@ -10,4 +10,4 @@
10
10
 
11
11
 
12
12
 
13
- (話だけでわかるかとも思うけど、サンプルを書けとかいわれるとちょっと面倒だなぁ...)
13
+ (話だけでわかるか? とも思うけど、サンプルを書けとかいわれるとちょっと面倒だなぁ...)