init() - The Arduino function that cost me a weekend, and a cautionary tale
Many of you reading this right now may not know this, but I am a high school senior. As such, weekends provide me with a much-needed break, and an opportunity to pursue my hobbies. One of those is playing the guitar (I really should get around to making a post about that some time), and another is (as I’m sure you’re aware) programming. This weekend (Feb 19th, 2023), I decided to do something I haven’t done in a while - dust out my old Arduino Uno, and perhaps do some low-level programming.
Why an Arduino? Well, I am an aspiring Computer Engineering major, and as such, I thought it might be a good idea to sharpen - or develop new - skills, in a field that I had much interest in, but not as much practical experience. I have rudimentary coding experience, mind you, but I would be lying if I said I had as much experience in the engineering aspect of the field.
And so I started assembling simple circuits, and writing simple programs to make those simple circuits work. But I quickly realized that this wasn’t as fun as it was when I was 11 (when I received this as a present). Shouldn’t there be more that goes on under the hood, beyond just digitalWrite(LED_BUILTIN,HIGH) and digitalWrite(LED_BUILTIN,LOW)?
I scoured the interent and quickly stumbled upon baremetal C programming tutorials for the Arduino Uno. These seemed to offer a nice balance between the readability of the Arduino C, and the low-level nature of, say, the AVR assembly language (I have programmed in ARM Assembly, but AVR scares me).
I know enough C at this point, that I was able to get the hang of it, and proceeded to create some simple digital IO circuits.
I decided to venture beyond the code that I saw on these websites, and implement my own toggle-swich circuit - press a push button to turn on an LED, press it again to turn it off.
I wrote the code for it, but since I was using baremetal C, I didn’t (couldn’t, really) use a lot of the existing documentation to help me write the code. I was mostly relying on my knowledge of registers and bitwise arithmetic. This might all seem incredibly trivial to you, the reader, but keep in mind that I had never done something quite like this before.
So, I finished writing the code and uploaded it, but it didn’t work. I pressed the button, and nothing would happen. There really isn’t too much to debug here: if input is 0 (since the input is pulled-up), implement the debouncing, and write a ‘1’ to the relevant bit to light the LED.
As a last resort of debugging: I removed my traditional int main(void) statement and while(1) loop altogether, and replaced it with the Arduino way of doing things: setup() and loop(). Lo and behold, it worked perfectly.
A SearX search brought me to this Arduino forum thread which (quite succinctly) states that the init() function is required if one insists on using the standard main() paradigm. Seven keystrokes later, and my original code was working, main() method and all! Apparently, this function is automatically called by the setup() function. What does it do? I’m not entirely sure. I found this webpage, which contains the source code for the function. It appears to initialize low-level hardware components such as timers, which would explain why my program (which relied on delay()), wasn’t working as expected.
Ultimately, I think this experience served as a cautionary tale: do not assume that any part of your code is working right, and inspect every part of it correctly. Also, check the forums! Doing that might have saved me hours of work debugging my code.