You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: content/learn/02.microcontrollers/04.debugging/debugging.md
+48-42Lines changed: 48 additions & 42 deletions
Original file line number
Diff line number
Diff line change
@@ -156,7 +156,7 @@ The Arduino® Zero board features an on-board debugger, the Atmel® Embedded Deb
156
156
157
157
Arduino® boards with a SAMD microcontroller feature native on-chip debug capabilities; these debugging capabilities can be used with an external ICD tool over JTAG or SWD interfaces. CMSIS-DAP compliant debug probes can be used with the Arduino IDE 2.0 out of the box without any configuration file; non-standard debug probes require a special configuration. Check out these tutorials to learn how to use an external ICD tool with SAMD based Arduino boards and the Arduino IDE 2.0:
158
158
159
-
*[Debugging with the Segger J-Link](https://docs.arduino.cc/tutorials/mkr-wifi-1010/mkr-jlink-setup).
159
+
*[Debugging with the SEGGER J-Link](https://docs.arduino.cc/tutorials/mkr-wifi-1010/mkr-jlink-setup).
160
160
*[Debugging with the Atmel-ICE](https://docs.arduino.cc/tutorials/mkr-wifi-1010/atmel-ice).
161
161
162
162
### Hardware Tools
@@ -224,7 +224,7 @@ Shown visual representation of the signal via SDR software can now be used to ve
224
224
225
225
## Debugging Techniques Example
226
226
227
-
A simple example will be used to demonstrate implementation of different debugging techniques and how they can be very useful for the development process. We are going to use [Arduino Nano 33 BLE](https://docs.arduino.cc/hardware/nano-33-ble) and use the LSM9DS1 inertial measurement unit's features to show the importance and ease of debugging process. The example code will be based on using [accelerometer](https://docs.arduino.cc/tutorials/nano-33-ble/imu_accelerometer), [gyroscope](https://docs.arduino.cc/tutorials/nano-33-ble/imu_gyroscope), and [magnetometer](https://docs.arduino.cc/tutorials/nano-33-ble/imu_magnetometer) at the same time, having the tasks to be executed in order to be able to obtain every value of the module.
227
+
A simple example will demonstrate the implementation of different debugging techniques and how they can be handy for the development process of a program in the Arduino® ecosystem. We will use the Arduino® Nano 33 BLE Sense board, and its onboard inertial measurement unit (IMU) features to show the debugging process's importance. The example code uses accelerometer, gyroscope, and magnetometer data simultaneously, having the tasks be executed to obtain every value:
228
228
229
229
```arduino
230
230
/*
@@ -243,11 +243,10 @@ A simple example will be used to demonstrate implementation of different debuggi
// Read accelerometer data in all three directions task
294
294
void accelerometer_task() {
295
295
if (IMU.accelerationAvailable()) {
296
-
Serial.println(F("Accelerometer Data Ready "));
296
+
Serial.println(F("- Accelerometer data ready"));
297
297
IMU.readAcceleration(x, y, z);
298
298
good++;
299
299
} else {
300
-
Serial.println(F("Accelerometer Data Not Ready "));
300
+
Serial.println(F("Accelerometer data not ready"));
301
301
bad++;
302
302
}
303
303
304
304
if (x > 0.1) {
305
305
x = 100 * x;
306
306
degreesX = map(x, 0, 97, 0, 90);
307
-
Serial.print(F("Tilting up "));
307
+
Serial.print(F("- Tilting up "));
308
308
Serial.print(degreesX);
309
309
Serial.println(F(" degrees"));
310
310
}
311
+
311
312
if (x < -0.1) {
312
313
x = 100 * x;
313
314
degreesX = map(x, 0, -100, 0, 90);
314
-
Serial.print(F("Tilting down "));
315
+
Serial.print(F("- Tilting down "));
315
316
Serial.print(degreesX);
316
317
Serial.println(F(" degrees"));
317
318
}
319
+
318
320
if (y > 0.1) {
319
321
y = 100 * y;
320
322
degreesY = map(y, 0, 97, 0, 90);
321
-
Serial.print(F("Tilting left "));
323
+
Serial.print(F("- Tilting left "));
322
324
Serial.print(degreesY);
323
325
Serial.println(F(" degrees"));
324
326
}
327
+
325
328
if (y < -0.1) {
326
329
y = 100 * y;
327
330
degreesY = map(y, 0, -100, 0, 90);
328
-
Serial.print(F("Tilting right "));
331
+
Serial.print(F("- Tilting right "));
329
332
Serial.print(degreesY);
330
333
Serial.println(F(" degrees"));
331
334
}
335
+
332
336
delay(1000);
333
337
}
334
338
339
+
// Gyroscope setup
335
340
void gyroscope_setup(){
336
-
Serial.print(F("Gyroscope sample rate = "));
341
+
Serial.print(F("- Gyroscope sample rate = "));
337
342
Serial.print(IMU.gyroscopeSampleRate());
338
343
Serial.println(F(" Hz"));
339
344
Serial.println();
340
-
Serial.println(F("Gyroscope in degrees/second"));
345
+
Serial.println(F("- Gyroscope in degrees/second"));
341
346
}
342
347
348
+
// Read gyroscope data in all three directions task
343
349
void gyroscope_task(){
344
350
if (IMU.gyroscopeAvailable()) {
345
351
IMU.readGyroscope(x, y, z);
346
-
Serial.println(F("GyroScope Data Ready "));
352
+
Serial.println(F("- Gyroscope data ready"));
347
353
good++;
348
354
} else {
349
-
Serial.println(F("GyroScope Data Not Ready "));
355
+
Serial.println(F("- Gyroscope data not ready"));
350
356
bad++;
351
357
}
352
358
353
359
if(y > plusThreshold){
354
-
Serial.println(F("Collision front"));
360
+
Serial.println(F("- Collision front"));
355
361
delay(500);
356
362
}
357
363
358
364
if(y < minusThreshold){
359
-
Serial.println(F("Collision back"));
365
+
Serial.println(F("- Collision back"));
360
366
delay(500);
361
367
}
362
368
363
369
if(x < minusThreshold){
364
-
Serial.println(F("Collision right"));
370
+
Serial.println(F("- Collision right"));
365
371
delay(500);
366
372
}
367
373
368
374
if(x > plusThreshold){
369
-
Serial.println(F("Collision left"));
375
+
Serial.println(F("- Collision left"));
370
376
delay(500);
371
377
}
372
378
}
373
379
380
+
// Read magnetometer data in all three directions task
374
381
void magnetometer_task(){
375
-
// read magnetic field in all three directions
376
382
IMU.readMagneticField(x, y, z);
377
383
378
-
if(x < 0){
384
+
if(x < 0){
379
385
ledvalue = -(x);
380
386
}
381
-
else{
387
+
else{
382
388
ledvalue = x;
383
389
}
384
390
@@ -387,23 +393,23 @@ void magnetometer_task(){
387
393
}
388
394
389
395
// For debugging purposes
390
-
void Save_Debug_Buffer(void) {
391
-
if (Count < DUMP_BUFFER_SIZE) {
392
-
GoodBuffer[Count] = good;
393
-
BadBuffer[Count] = bad;
396
+
void save_debug_buffer(void) {
397
+
if (count < DUMP_BUFFER_SIZE) {
398
+
GoodBuffer[count] = good;
399
+
BadBuffer[count] = bad;
394
400
Disp_Debug_Buffer();
395
-
Count++;
401
+
count++;
396
402
}
397
403
}
398
404
399
-
void Disp_Debug_Buffer(){
405
+
void disp_debug_buffer(){
400
406
// Simple log of Good or Bad Pass Marks during runtime
401
407
Serial.println(F("\n Strategic Array Dump Result >>"));
402
408
Serial.print(F("Good Marks: "));
403
-
Serial.println(GoodBuffer[Count]);
409
+
Serial.println(GoodBuffer[count]);
404
410
405
411
Serial.print(F("Bad Marks: "));
406
-
Serial.println(BadBuffer[Count]);
412
+
Serial.println(BadBuffer[count]);
407
413
}
408
414
409
415
void debug_stop(){
@@ -412,19 +418,19 @@ void debug_stop(){
412
418
}
413
419
```
414
420
415
-
The complete code as shown unifies accelerometer, gyroscope, and magnetometer into a single code structure. As it involves tasks from different modules, it is separated into different functions and executed in a more identifiable manner. It includes the**Strategic Array Dump** to understand exactly how the code operates. The `good` and `bad` marks are located at the points of interest, and will dump into assigned arrays to be able to display at the end of the code.
421
+
As shown, the complete code unifies the accelerometer, gyroscope, and magnetometer into a single code structure. As it involves tasks from different modules, it is separated into different functions and executed in a more identifiable manner. The code includes a**trace code**technique for debugging (dump into an array) to understand precisely how the code operates. The `good` and `bad` marks are located at the points of interest in the code and will dump into assigned arrays to be able to display at the end of the code.
416
422
417
-
It is crucial to know when to stop the code to be able to debug the code. While the code above is capable of debugging at runtime, it is much easier to debug knowing when to or how to stop the code operation. For instance, stopping within first run, will give you following result.
423
+
It is crucial to know when to stop the code from debugging. While the code shown above can be debugged at runtime, it is much easier to know when to stop or how to stop the code operation. For instance, stopping within the first run gives the following result:
418
424
419
425

420
426
421
-
In the serial monitor we can observe that it has 1 good mark and 1 bad mark. The good mark came from the gyroscope having ready the data for the use, while the bad mark comes from the accelerometer as the data was not ready. So it is possible to see the accelerometer does not have enough time to get the data ready before it gets to the measurement task. We can try by running certain amount of instances before it gets to array dump sector, and the result can be seen as follows.
427
+
In the Arduino Serial Monitor, we can observe that it has a `1` good mark and a `1` bad mark. The good mark came from the gyroscope having ready the data for use, while the bad mark came from the accelerometer as the data was not ready. So it is possible to see that the accelerometer does not have enough time to get the data ready before it gets to the measurement task. We can try by running a certain number of instances before it gets to the array dump sector, and the result can be seen as follows:
The accelerometer was able to perform its task without any issue with the exception of the first runtime instance, resulting in 9 good marks but 1 bad mark due to this behaviour. By this, it is possible to know the code structure does not misbehave, but for the first time when the device is starting, the accelerometer requires more time to be able to get the data ready in the first instance. The `Serial.println(F())` of module setups, and task runtimes also show us if the code was able to get past the operations without any issue.
431
+
The accelerometer performed its task without any issue except the first runtime instance, resulting in `9` good marks but `1` bad mark due to this behavior. The `Serial.println(F())` instruction of module setups and task runtimes also shows us if the code could get past the operations without any issue. By this, it is possible to know the code structure does not misbehave, but for the first time when the device is starting, the accelerometer requires more time to get the data ready in the first instance.
426
432
427
-
Additionally, it is possible to modify the loop code by adding simply GPIO 13 to drive High and Low to measure the time it takes to complete 3 module tasks. It will be also helpful to understand the power consumption it draws from this runtime instance.
433
+
Additionally, it is possible to modify the loop code by simply adding a `digitalWrite(LED_BUILTIN, HIGH)` instruction and a `digitalWrite(LED_BUILTIN, LOW)` instruction to measure the time it takes to complete the three module tasks. It will also be helpful to understand the power consumption it draws from this runtime instance:
428
434
429
435
```arduino
430
436
void loop() {
@@ -451,9 +457,9 @@ Debugging is a necessary step for developing robust and reliable embedded system
451
457
***Localization**: this phase involves narrowing the range of possibilities until the bug can be isolated to a specific code segment in the embedded software.
452
458
***Correction**: this phase involves eradicating the bug from the software.
453
459
454
-
Knowing the potential causes of bugs allows us to adopt strategies that minimize their occurrence. To aid this process, lots of different debugging technniques and external devices are present. Maybe some software designs does not require the usage of external debuggers for example, but when the software involves different levels of requirements and specially when it requires scalability, things change drastically for the development process. The debugging techniques and the external debuggers will support this development process, thus granting refined software. You will know how the device will behave in most cases with the software, its computational performance, and even achieve non-power hungry devices due to clean memory management.
460
+
Knowing the potential causes of bugs allows us to adopt strategies that minimize their occurrence. Many different debugging techniques and external devices are present to aid this process. Maybe some software designs do not require the usage of external debuggers, for example. However, when the software involves different requirements, especially scalability, things change drastically for the development process. The debugging techniques and the external debuggers will support this development process, thus granting sophisticated software. In most cases, we will know how the device will behave with the software, its computational performance, and even achieve non-power hungry devices due to clean memory management.
455
461
456
-
The debugging may be an overlooked aspect of the development, but it is the most serious yet crucial tool that exists for the development. If you desire to develop a genuine device, the debugging process should always be implemented, to achieve its genuine performance.
462
+
Debugging may be an overlooked aspect of development, but it is the most serious yet crucial tool for development. If we desire to develop a robust and reliable device, the debugging process should consistently be implemented to achieve this goals.
0 commit comments