/
aidecktest.c
471 lines (386 loc) · 11.5 KB
/
aidecktest.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
/*
* || ____ _ __
* +------+ / __ )(_) /_______________ _____ ___
* | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \
* +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/
* || || /_____/_/\__/\___/_/ \__,_/ /___/\___/
*
* Crazyflie control firmware
*
* Copyright (C) 2011-2021 Bitcraze AB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, in version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* aidecktest.c - Testing of AI deck in production
*/
#define DEBUG_MODULE "AIDECK-TEST"
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "stm32fxxx.h"
#include "config.h"
#include "console.h"
#include "uart1.h"
#include "debug.h"
#include "deck.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "log.h"
#include "param.h"
#include "uart1.h"
#include "uart2.h"
//#define DEBUG_PRINT_COM DEBUG_PRINT
#define DEBUG_PRINT_COM(...)
#define START_UP_BYTE 0xBC
static bool isInit;
static void aitdecktestInit(DeckInfo *info)
{
if (isInit)
return;
DEBUG_PRINT("Initialize AI-deck test\n");
// FOr the GAP8
uart1Init(115200);
// For the NINA
uart2Init(115200);
isInit = true;
}
static bool testOnNina(const uint8_t command, const uint8_t expected)
{
uint8_t byte;
uart2Putchar(command);
if (uart2GetDataWithDefaultTimeout(&byte) == true)
{
DEBUG_PRINT_COM("[NINA] Received: 0x%02X\r\n", byte);
if (byte == expected)
{
return true;
}
}
DEBUG_PRINT_COM("[NINA] Received timeout!\r\n");
return false;
}
static bool testOnNinaMask(const uint8_t command, uint8_t *byte)
{
uart2Putchar(command);
if (uart2GetDataWithDefaultTimeout(byte) == true)
{
DEBUG_PRINT_COM("Received mask: 0x%02X\r\n", *byte);
return true;
}
return false;
}
static bool testOnGAP8(const uint8_t command, const uint8_t expected)
{
uint8_t byte;
uint8_t timeout_counter = 0;
uart1Putchar(command);
while(timeout_counter < 5){
if (uart1GetDataWithDefaultTimeout(&byte) == true)
{
DEBUG_PRINT_COM("[GAP8] Received: 0x%02X\r\n", byte);
if (byte == expected)
{
return true;
}
}
timeout_counter++;
}
return false;
}
/* At startup NINA and GAP8 should send 0xBC */
/* NINA command set
* 0x01 - Button has been high (1=true, 0=false)
* 0x02 - Button has been low (1=true, 0=false)
* 0x03 - Reset button low status (1=pass,0=fail) (will probably just return pass, it's just for setting)
* 0x04 - Read GPIO mask (read out bitmask bits 0-5 as XX54 3210)
* 0x05 - Reset GAP8 though NINA (1=pass,0=fail) (will probably just return pass, it's just for setting)
*/
/* GAP8 command set
* 0x01 - Test Hyper flash (1=pass, 0=fail)
* 0x02 - Test camera (1=pass, 0=fail)
* 0x03 - Test I2C by reading EEPROM
* 0x40 - 5 bits for GPIO output [XA54 3210] where A=1 and 0-5 is the GPIOs in the list below (1=pass, 0=fail) (will probably just return pass, it's just for setting)
*/
/* GPIO list for 0x40
* 0 - GAP8_SPI_MISO
* 1 - GAP8_GPIO_NINA_IO
* 2 - GAP8_SPI_MOSI
* 3 - NINA_GPIO_GAP8_IO
* 4 - GAP8_SPI_CS0
* 5 - GAP8_SPI_CLK
*/
/* GPIO list for 0xC0
* 0 - I2C SDA
* 1 - I2C SCL
*/
/* Bit - Function (1=fail, 0=pass)
*
* 0 - Nina button high
* 1 - Nina button low (by press)
* 2 - Nina button low (by IO)
* 3-8 - GPIO NINA <-> GAP8
* 9-14 - GPIO NINA <-> GAP8 inverted
* 15 - Hyper flash
* 16 - Camera
* 17 - I2C
* 18 - GAP8 reset though NINA
* 19 - GAP8 reset tough RST
* 20 - NINA reset tough RST
*/
uint32_t testmask = 0x01FFFFFUL; // Not true, set all bits in mask to 1
uint8_t testdone; // Set to 1 when testing is completed
#define NINA_INIT_CHAR 0xBC
#define GAP8_INIT_CHAR 0xBC
#define NINA_BOOT_HIGH 0x01
#define NINA_BOOT_HIGH_EXPECTED 0x01
#define NINA_BOOT_HIGH_POS 0x00
#define NINA_BOOT_LOW 0x02
#define NINA_BOOT_LOW_EXPECTED 0x01
#define NINA_BOOT_LOW_POS 0x01UL
#define NINA_BOOT_LOW_RESET 0x03
#define NINA_BOOT_LOW_RESET_EXPECTED 0x01
#define NINA_BOOT_LOW_IO_POS 0x02UL
#define GAP8_GPIO_COMMAND 0x40
#define GAP8_GPIO_MASK 0x15
#define GAP8_GPIO_MASK_EXPECTED 0x01UL
#define NINA_GAP8_GPIO_COMMAND 0x04
#define NINA_GAP8_GPIO_POS 0x03
#define NINA_GAP8_GPIO_INV_POS 0x09UL
#define GAP8_HYPER_COMMAND 0x01
#define GAP8_HYPER_EXPECTED 0x01
#define GAP8_HYPER_POS 0x0FUL
#define GAP8_CAMERA_COMMAND 0x02
#define GAP8_CAMERA_EXPECTED 0x01
#define GAP8_CAMERA_POS 0x10UL
#define GAP8_I2C_COMMAND 0x03
#define GAP8_I2C_EXPECTED 0x01
#define GAP8_I2C_POS 0x11UL
#define NINA_GAP8_RST_COMMAND 0x05
#define NINA_GAP8_RST_EXPECTED 0x01
#define NINA_GAP8_RST_POS 0x12
#define CF2_GAP8_RST_POS 0x13
#define CF2_NINA_RST_POS 0x14
static bool aitdecktestTest()
{
bool testHasBeenTriggered = false;
uint8_t byte;
uint8_t gpio_mask;
DEBUG_PRINT("Running AI-deck test, waiting for button press\r\n");
//Reset GAP8 and NINA to start with
pinMode(DECK_GPIO_IO4, OUTPUT);
digitalWrite(DECK_GPIO_IO4, LOW);
vTaskDelay(10);
digitalWrite(DECK_GPIO_IO4, HIGH);
pinMode(DECK_GPIO_IO4, INPUT_PULLUP);
// Wait for the NINA to start
vTaskDelay(M2T(1000));
// Empty the buffer from NINA
while (uart2GetDataWithDefaultTimeout(&byte) == true)
;
while (uart1GetDataWithDefaultTimeout(&byte) == true)
;
while (!testHasBeenTriggered)
{
// Send test for button low to NINA
if (testOnNina(NINA_BOOT_LOW, NINA_BOOT_LOW_EXPECTED) == true)
{
testmask &= ~(1UL << NINA_BOOT_LOW_POS);
testHasBeenTriggered = true;
}
vTaskDelay(M2T(100));
}
// Send test for button high NINA
if (testOnNina(NINA_BOOT_HIGH, NINA_BOOT_HIGH_EXPECTED) == true)
{
testmask &= ~(1UL << NINA_BOOT_HIGH_POS);
DEBUG_PRINT("NINA button test [OK]\r\n");
}
else
{
DEBUG_PRINT("NINA button test [FAILED]\r\n");
}
if (testOnNina(NINA_BOOT_LOW_RESET, NINA_BOOT_LOW_RESET_EXPECTED) == true)
{
// Pull boot and read out button low on NINA
pinMode(DECK_GPIO_IO1, OUTPUT);
digitalWrite(DECK_GPIO_IO1, LOW);
vTaskDelay(150);
digitalWrite(DECK_GPIO_IO1, HIGH);
// Send reset button status to NINA (not done on NINA yet)
if (testOnNina(NINA_BOOT_LOW, NINA_BOOT_LOW_EXPECTED) == true)
{
testmask &= ~(1UL << NINA_BOOT_LOW_IO_POS);
DEBUG_PRINT("NINA boot pin test [OK]\r\n");
}
else
{
DEBUG_PRINT("NINA boot pin test [FAILED]\r\n");
}
}
// Send test for GPIO mask to GAP8 (should be optimized to it's inveterd to neighbours)
// In GAP8, the command (GAP8_GPIO_MASK 0x04) should be removed from the mask so that it is like
// GAP8_GPIO_MASK again
if (testOnGAP8(GAP8_GPIO_COMMAND|GAP8_GPIO_MASK, GAP8_GPIO_MASK_EXPECTED) == true)
{
vTaskDelay(M2T(100));
// Send test for GPIO mask to NINA
if (testOnNinaMask(NINA_GAP8_GPIO_COMMAND, &gpio_mask) == true)
{
uint32_t gpio_mask_result = (uint32_t)0X3F << NINA_GAP8_GPIO_POS;
gpio_mask_result ^= 0x01FFFFF;
gpio_mask_result |= (uint32_t)(gpio_mask ^ GAP8_GPIO_MASK) << NINA_GAP8_GPIO_POS;
testmask &= gpio_mask_result;
DEBUG_PRINT("GAP8->NINA gpio test [OK]\r\n");
}
else
{
DEBUG_PRINT("GAP8->NINA gpio test [FAILED]\r\n");
}
}
else
{
DEBUG_PRINT("Set GAP8 gpio mask [FAILED]\r\n");
}
vTaskDelay(M2T(100));
uint8_t not_mask = (~GAP8_GPIO_MASK) & 0X3F;
// Send test for ~ GPIO mask to GAP8
if (testOnGAP8(GAP8_GPIO_COMMAND | not_mask, GAP8_GPIO_MASK_EXPECTED) == true)
{
vTaskDelay(M2T(100));
// Send test for ~ GPIO mask to NINA
if (testOnNinaMask(NINA_GAP8_GPIO_COMMAND, &gpio_mask) == true)
{
uint32_t gpio_mask_result = (uint32_t)0X3F << NINA_GAP8_GPIO_INV_POS;
gpio_mask_result ^= 0x01FFFFF;
gpio_mask_result |= (uint32_t)(gpio_mask ^ ((~GAP8_GPIO_MASK) & 0X3F)) << NINA_GAP8_GPIO_INV_POS;
testmask &= gpio_mask_result;
DEBUG_PRINT("GAP8->NINA gpio not-test [OK]\r\n");
}
else
{
DEBUG_PRINT("GAP8->NINA gpio not-test [FAILED]\r\n");
}
}
else
{
DEBUG_PRINT("Set GAP8 gpio not-mask [FAILED]\r\n");
}
// Send test for Hyper flash to GAP8
if (testOnGAP8(GAP8_HYPER_COMMAND, GAP8_HYPER_EXPECTED) == true)
{
testmask &= ~(1UL << GAP8_HYPER_POS);
DEBUG_PRINT("GAP8 Hyper test [OK]\r\n");
}
else
{
DEBUG_PRINT("GAP8 Hyper test [FAILED]\r\n");
}
// Send test for Camera to GAP8
if (testOnGAP8(GAP8_CAMERA_COMMAND, GAP8_CAMERA_EXPECTED) == true)
{
testmask &= ~(1UL << GAP8_CAMERA_POS);
DEBUG_PRINT("GAP8 Camera test [OK]\r\n");
}
else
{
DEBUG_PRINT("GAP8 Camera test [FAILED]\r\n");
}
// Test I2C by GAP8 by reading the EEPROM for the address and magic number
// MAGIC 0x43427830
// EEPROM_I2C_ADDR 0x50
// NOTE: should be not be run at startup!
if (testOnGAP8(GAP8_I2C_COMMAND, GAP8_I2C_EXPECTED) == true)
{
testmask &= ~(1UL << GAP8_I2C_POS);
DEBUG_PRINT("GAP8 I2C test [OK]\r\n");
}
else
{
DEBUG_PRINT("GAP8 I2C test [FAILED]\r\n");
}
// Test RST of GAP8 though NINA
// (listen on GAP8 uart for hello)
if (testOnNina(NINA_GAP8_RST_COMMAND, NINA_GAP8_RST_EXPECTED) == true)
{
while (uart1GetDataWithDefaultTimeout(&byte) == true)
{
if (byte == GAP8_INIT_CHAR)
{
testmask &= ~(1UL << NINA_GAP8_RST_POS);
DEBUG_PRINT("NINA->GAP8 reset [OK]\r\n");
break;
}
}
if (byte != GAP8_INIT_CHAR)
{
DEBUG_PRINT("NINA->GAP8 reset [FAILED]\r\n");
}
}
else
{
DEBUG_PRINT("NINA->GAP8 reset, NINA not responding. [FAILED]\r\n");
}
//Test RST of both GAP8 and NINA by pulling reset
pinMode(DECK_GPIO_IO4, OUTPUT);
digitalWrite(DECK_GPIO_IO4, LOW);
vTaskDelay(10);
digitalWrite(DECK_GPIO_IO4, HIGH);
pinMode(DECK_GPIO_IO4, INPUT);
// (listen on GAP8 and NINA uart for 0xbc)
while (uart2GetDataWithDefaultTimeout(&byte) == true)
{
if (byte == NINA_INIT_CHAR)
{
testmask &= ~(1UL << CF2_NINA_RST_POS);
DEBUG_PRINT("NINA reset [OK]\r\n");
break;
}
}
if (byte != NINA_INIT_CHAR)
{
DEBUG_PRINT("NINA reset [FAILED]\r\n");
}
while (uart1GetDataWithDefaultTimeout(&byte) == true)
{
if (byte == GAP8_INIT_CHAR)
{
DEBUG_PRINT("GAP8 reset [OK]\r\n");
testmask &= ~(1UL << CF2_GAP8_RST_POS);
break;
}
}
if (byte != GAP8_INIT_CHAR)
{
DEBUG_PRINT("GAP8 reset [FAILED]\r\n");
}
// Set all tests done
DEBUG_PRINT("AI deck test mask: 0x%08X\r\n", testmask);
testdone = 1;
return (testmask == 0);
}
static const DeckDriver aitest_deck = {
.name = "bcAIDeckTest",
.usedPeriph = DECK_USING_UART1,
.usedGpio = DECK_USING_IO_4,
.init = aitdecktestInit,
.test = aitdecktestTest,
};
DECK_DRIVER(aitest_deck);
LOG_GROUP_START(aidecktest)
LOG_ADD(LOG_UINT32, testresult, &testmask)
LOG_ADD(LOG_UINT8, done, &testdone)
LOG_GROUP_STOP(aidecktest)