The board get bricked once my code uploaded

I am trying to write my own keypad with Arduino.

Once I uploaded my code, the board get bricked and no more upload is possible.

I have tried three pro micro compatible boards and two genuine arduino leonardo booard and now I have five bricks...

FYI, I have tested the leonardo board with blink example before uploading my custom code and there was no problem before upload.

Also, I have tried the known method to upload blank file with double pressing reset button but all failed with all five boards.

With double pressing reset button, the bootloader device came up in device list but upload ends with fail.

Here's the full upload log with verbose option:

Sketch uses 6664 bytes (23%) of program storage space. Maximum is 28672 bytes.
Global variables use 318 bytes (12%) of dynamic memory, leaving 2242 bytes for local variables. Maximum is 2560 bytes.
Waiting for upload port...
Upload port found on COM9

avrdude: Version 6.3-20190619
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2014 Joerg Wunsch

         System wide configuration file is "C:\Users\sha\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17/etc/avrdude.conf"

         Using Port                    : COM9
         Using Programmer              : avr109
         Overriding Baud Rate          : 57600
"C:\Users\sha\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17/bin/avrdude" "-CC:\Users\sha\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17/etc/avrdude.conf" -v -V -patmega32u4 -cavr109 "-PCOM9" -b57600 -D "-Uflash:w:C:\Users\sha\AppData\Local\Temp\arduino\sketches\89A81B1A7E1699C51D7235EE5FA1BE73/tenkey.ino.hex:i"
         AVR Part                      : ATmega32U4
         Chip Erase delay              : 9000 us
         PAGEL                         : PD7
         BS2                           : PA0
         RESET disposition             : dedicated
         RETRY pulse                   : SCK
         serial program mode           : yes
         parallel program mode         : yes
         Timeout                       : 200
         StabDelay                     : 100
         CmdexeDelay                   : 25
         SyncLoops                     : 32
         ByteDelay                     : 0
         PollIndex                     : 3
         PollValue                     : 0x53
         Memory Detail                 :

                                  Block Poll               Page                       Polled
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           eeprom        65    20     4    0 no       1024    4      0  9000  9000 0x00 0x00
           flash         65     6   128    0 yes     32768  128    256  4500  4500 0x00 0x00
           lfuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           hfuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           efuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           lock           0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           calibration    0     0     0    0 no          1    0      0     0     0 0x00 0x00
           signature      0     0     0    0 no          3    0      0     0     0 0x00 0x00

         Programmer Type : butterfly
         Description     : Atmel AppNote AVR109 Boot Loader

Connecting to programmer: .
Found programmer: Id = "CATERIN"; type = S
    Software Version = 1.0; No Hardware Version given.
Programmer supports auto addr increment.
Programmer supports buffered memory access with buffersize=128 bytes.

Programmer supports the following devices:
    Device code: 0x44

avrdude: devcode selected: 0x44
avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e9587 (probably m32u4)
avrdude: reading input file "C:\Users\sha\AppData\Local\Temp\arduino\sketches\89A81B1A7E1699C51D7235EE5FA1BE73/tenkey.ino.hex"
avrdude: writing flash (6664 bytes):

Writing | ################################################## | 100% 0.50s

avrdude: 6664 bytes of flash written

avrdude done.  Thank you.

And, I doubt my code could ruin the hardware but who knows? here's my code:

#include <Keyboard.h>

template<size_t N>
constexpr inline auto length(int (&array)[N]) -> size_t { return N; }

constexpr int OFF = LOW;
constexpr int ON = HIGH;

int columns[] = {21, 20, 19, 18};
int rows[] = {5, 6, 7, 8, 9};

struct Key {
  Key(char code = 0x0): code{code} {}
  char code = 0x0;
  int state = OFF;
};

Key keys[length(rows)][length(columns)] = {
  {KEY_NUM_LOCK, 0x54 , 0x55, 0x56},
  {},
  {},
  {},
};


int debounce = 10;

auto scan() noexcept -> void
{
  Serial.println("start scan");
  const auto nrows = length(rows);
  const auto ncols = length(columns);
  for (int r = 0; r < rows; ++r) {
    const auto rowPin = rows[r];
    digitalWrite(rowPin, ON);
    for (int c = 0; c < ncols; ++c) {
      auto &key = keys[r][c];
      if (!key.code)
        continue;
      const auto state = digitalRead(columns[c]);
      if (state != key.state) {
        // if (key.state == OFF)
          // Keyboard.release(key.code);
        // else
          // Keyboard.press(key.code);
        Serial.println((int)key.code);
        key.state = state;
      }
    }
    digitalWrite(rowPin, OFF);
  }
}

void setup() {  // initialize the buttons' inputs:
  for (int row : rows) {
    pinMode(row, OUTPUT);
    digitalWrite(row, OFF);
  }
  for (int column : columns)
    pinMode(column, INPUT);
  Serial.begin(9600);
  // initialize mouse control:
  Keyboard.begin();
}

void loop() {
  scan();
  delay(100);
}

Where did the upload fail? The log you posted shows a successful upload.

I have no idea.
As you said, the log shows successful but it ends with error and the device does not come up in COM port list which makes me think bootloader reset failed. Here's a screenshot:

int columns[] = {21, 20, 19, 18};

Do all of these pin numbers exist on the Arduinos that you are using ?

This technique should work if you have a genuine SparkFun Pro Micro, but the common Chinese Pro Micro clones ship with a different bootloader that doesn't have support for the double reset.

You can follow these instructions to recover the Pro Micro clones:

  1. Select Sketch > Upload from the Arduino IDE menus.
  2. Watch the black "Output" panel at the bottom of the Arduino IDE window until you see something like this:
    Sketch uses 444 bytes (1%) of program storage space. Maximum is 30720 bytes.
    Global variables use 9 bytes (0%) of dynamic memory, leaving 2039 bytes for local variables.
    Maximum is 2048 bytes.
    
  3. Immediately press and release the reset button on the Arduino board.

The upload should now finish successfully.

If you find that the board still doesn't produce a port while the bootloader is not activated, the problem may be caused by your sketch code. You can verify this by uploading a simple sketch like the one from File > Examples > 01.Basics > BareMinimum in the Arduino IDE menus. If the uploads work normally after uploading that sketch, but not after uploading the previous sketch you were using, then you will know the issue is caused by that other sketch code.

Which port did you select in IDE for normal communication? The port monitor complains it isn't able to connect to com9. That's obvious, because Com9 is used as upload port only. When the upload is finished, this port no longer exists.
On micro/Leonardo the upload port is different from the port used by serial monitor.

The upload finished successfully. It seems to be a problem with connection after the upload. But that is obvious if he tries to connect with the upload port.

Thanks for pointing that out. I see now that the mentioned error is only the notification Serial Monitor attempting to connect to the port. This notification is normal and expected in the case where the uploaded sketch kills the USB CDC serial port because of course Serial Monitor can't reconnect to the port if it doesn't exist.

So the focus must be exclusively on fixing the bug in the sketch that breaks the USB code. Once that is solved, the notification about Serial Monitor being unable to reconnect will no longer occur. It is only serving as a "red herring" at this point.

Did you look in device manager for the Com port after uploading?

@UKHeliBob As far as I know, yes.

@MicroBahner Yes, I checked the device manager of Windows and no device for my board is shown.

Is it possible for my code to break my board?

I have tried what @ptillisch mentioned and it seems it work once blank code uploaded.
However, if I upload my code, the COM port for my board disappears again.
So I think, definitely, my code do something wrong, but I don't know what it is.

By the way, my leonardos are genuines although pro micros are clone.

In theory, yes. For example, if you had a pin connected to ground it to OUTPUT HIGH in the sketch , that would create a short circuit that could do physical damage to the board. Or if you made a sketch that wrote to the EEPROM thousands of times that would do physical damage by wearing out the EEPROM (which is only rated for a certain number of write cycles).

But in the case where you sketch stops the USB code from working, that doesn't do any physical damage. It is what we might call a "soft brick", where it puts the board into a state where it doesn't work as you expected, but it can be recovered into a normally functional state by performing the right procedure.

I agree.

My advice is to take the "divide and conquer" approach to troubleshooting. The goal is to produce a minimal demonstration sketch that contains only the absolute minimum of code required to produce the fault. Remove a section of code from your sketch and then upload it to the board. If the problem still occurs, then you know that code was not relevant to the problem and you can leave it out of the demo sketch. Conversely, if the fault no longer occurs after removing that section of code, you know it is relevant to the problem.

Continue doing that until you have distilled it down as far as possible. Doing this will make the situation easier to understand by removing all irrelevant complexity from the system.

I find that often by the time I have completed this work the cause of the fault has become clear to me. Even if it doesn't, you can then share this minimal, reproducible, verifiable example (MCVE) here on the forum. It will be of value to the helpers here.

1 Like

Well, after getting 4 bricks in a row, I never connected anything with last leonardo, so it is not wiring issue.
Anyway, I will try to narrow down. Thank you for advice.

I agree. I was only answering your previous "Is it possible" question in general. It is possible under certain conditions, but we don't see any evidence whatsoever that is the case in this particular situation.

I am intrigued

How are these pins labelled on the Leonardo ?

1 Like

I think you must wait until the Com port is established after Serial.begin:

  Serial.begin(9600);
  while(!Serial);   //wait until Com port is established
  // initialize mouse control:
  Keyboard.begin();
...

otherwise Keyboard.begin() will abort establishing the Com port

/tmp/arduino_modified_sketch_824552/BlinkWithoutDelay.ino:33:23: warning: ISO C++ forbids comparison between pointer and integer [-fpermissive]
   for (int r = 0; r < rows; ++r) {
                       ^~~~

Be careful with the key scan, unless the switches are diode isolated, you do not want to have more than one row pin in OUTPUT mode at the same time, otherwise pressing two keys in different rows simultaneously can short the outputs together. Keep the row pins in INPUT mode, only setting to OUTPUT when scanning a particular row, then back to INPUT. See the Keypad library for how this is done.

1 Like

Yeah, and you should definitely activate all warnings. This line must be
for (int r = 0; r < nrows; ++r) {
With 'rows' only your for loop reaches far beyond the array 'rows' and destroys arbitrary ram space. Anything can happen - even destroying the USB connection ( that's what is happening ).

1 Like