Getting up and running on SparkFun ProMicro without Arduino IDE and using C to program the ProMicro.

So this was an effort in reverse engineering. There were a lot of things that I had to strip apart in order to get this to work.  As I suggested before, in the Arduino IDE under File>Preferences there is a place to edit the preferences.txt file (you might have to get there some other way), and in there set the build.verbose and upload.verbose to True.  This allows you see the output of how the files are being compiled and built and then being uploaded onto the SparkFun ProMicro. Here is a great high level overview on how avr-gcc chain works.

The first thing I did was create 2 very different sets of code that would allow me to debug if anything failed at a certain step. The 2 sets of code I created were:

The first one was just a simple code that blinks 2 leds and this was done entirely in the arduino IDE and used all the functions that arduino provides:

/* Pro Micro Test Code
 by: Nathan Seidle
 modified by: Jim Lindblom
 SparkFun Electronics
 date: September 16, 2013
 license: Public Domain - please use this code however you'd like.
 It's provided as a learning tool.

This code is provided to show how to control the SparkFun
 ProMicro's TX and RX LEDs within a sketch. It also serves
 to explain the difference between Serial.print() and
 Serial1.print().
*/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>

//int RXLED = 17; // The RX LED has a defined Arduino pin
// The TX LED was not so lucky, we'll need to use pre-defined
// macros (TXLED1, TXLED0) to control that.
// (We could use the same macros for the RX LED too -- RXLED1,
// and RXLED0.)

void setup()
{
 //pinMode(RXLED, OUTPUT); // Set RX LED as an output
 //setting up PBO
 (*(volatile unsigned char *)(0x24)) = 0x1; //setting the 0th bit in DDRB to 1 so that it can set up for output
 (*(volatile unsigned char *)(0x25)) = 0x0; //setting the 0th bit in PortB to 0 so that it can set output low

//setting up PD5
 (*(volatile unsigned char *)(0x2A)) = 0x20; //setting the 5th bit in DDRB to 1 so that it can set up for output
 (*(volatile unsigned char *)(0x2B)) = 0x0; //setting the 5th bit in PortB to so that it can set output low

// TX LED is set as an output behind the scenes

Serial.begin(9600); //This pipes to the serial monitor
 Serial1.begin(9600); //This is the UART, pipes to sensors attached to board
}

void loop()
{
 //Serial.println("Hello world"); // Print "Hello World" to the Serial Monitor
 Serial1.println("Hello!"); // Print "Hello!" over hardware UART


 //digitalWrite(RXLED, LOW); // set the LED on
 (*(volatile unsigned char *)(0x25)) = 0x0;
 //Serial.println((*(volatile unsigned char *)(0x23)));
 
 (*(volatile unsigned char *)(0x2B)) = 0x20; //setting the 5th bit in PortB to so that it can set output high
 //TXLED0; //TX LED is not tied to a normally controlled pin

delay(1000); // wait for a second
//
 //digitalWrite(RXLED, HIGH); // set the LED off
 (*(volatile unsigned char *)(0x2B)) = 0x0; //setting the 5th bit in PortB to so that it can set output low
 
 //TXLED1;
 (*(volatile unsigned char *)(0x25)) = 0x1;
 //Serial.println((*(volatile unsigned char *)(0x23)));


 delay(1000); // wait for a second


}

 

The second one was a program that sent Pin B5 high and low as fast as it could.  This could addressed the DDRB and PortB directly with the registers and removed as much dependency on arduino as possible. The code was:

blah

#include <avr/io.h>
#include <util/delay.h>

#define BLINK_DELAY_MS 100

int main (void)
{
 /* set pin 5 of PORTB for output*/
 (*(volatile unsigned int*)(0x24)) |= (1<<(5));

while(1) {
 /* set pin 5 high to turn led on */
 (*(volatile unsigned int*)(0x25)) |= (1<<(5));
 
 /* set pin 5 low to turn led off */
 (*(volatile unsigned int*)(0x25)) &= (0<<(5));
 }
 }

I had to use avr/io and util/delay.h because those are atmel avr functions not ardunio functions. As you can see this is written in code.  I tested both the codes in Arduino and they were working. This confirmed that code base I had was working completely.

The next step was to take the output of the arduino and start breaking it apart in order to get a better understanding of what is happening.  Here is the arduino output:

 

home/ashwini/Downloads/arduino-1.8.3/arduino-builder -dump-prefs -logger=machine -hardware /home/ashwini/Downloads/arduino-1.8.3/hardware -hardware /home/ashwini/.arduino15/packages -tools /home/ashwini/Downloads/arduino-1.8.3/tools-builder -tools /home/ashwini/Downloads/arduino-1.8.3/hardware/tools/avr -tools /home/ashwini/.arduino15/packages -built-in-libraries /home/ashwini/Downloads/arduino-1.8.3/libraries -libraries /home/ashwini/Arduino/libraries -fqbn=SparkFun:avr:promicro:cpu=8MHzatmega32U4 -ide-version=10803 -build-path /tmp/arduino_build_569596 -warnings=all -build-cache /tmp/arduino_cache_732047 -prefs=build.warn_data_percentage=75 -verbose /home/ashwini/Arduino/blinky_c_no_serial_for_avrgcc/blinky_c_no_serial_for_avrgcc.ino

/home/ashwini/Downloads/arduino-1.8.3/arduino-builder -compile -logger=machine -hardware /home/ashwini/Downloads/arduino-1.8.3/hardware -hardware /home/ashwini/.arduino15/packages -tools /home/ashwini/Downloads/arduino-1.8.3/tools-builder -tools /home/ashwini/Downloads/arduino-1.8.3/hardware/tools/avr -tools /home/ashwini/.arduino15/packages -built-in-libraries /home/ashwini/Downloads/arduino-1.8.3/libraries -libraries /home/ashwini/Arduino/libraries -fqbn=SparkFun:avr:promicro:cpu=8MHzatmega32U4 -ide-version=10803 -build-path /tmp/arduino_build_569596 -warnings=all -build-cache /tmp/arduino_cache_732047 -prefs=build.warn_data_percentage=75 -verbose /home/ashwini/Arduino/blinky_c_no_serial_for_avrgcc/blinky_c_no_serial_for_avrgcc.ino

Using board 'promicro' from platform in folder: /home/ashwini/.arduino15/packages/SparkFun/hardware/avr/1.1.6

Using core 'arduino' from platform in folder: /home/ashwini/Downloads/arduino-1.8.3/hardware/arduino/avr

Detecting libraries used...

"/home/ashwini/Downloads/arduino-1.8.3/hardware/tools/avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -flto -w -x c++ -E -CC -mmcu=atmega32u4 -DF_CPU=8000000L -DARDUINO=10803 -DARDUINO_AVR_PROMICRO -DARDUINO_ARCH_AVR -DUSB_VID=0x1b4f -DUSB_PID=0x9204 '-DUSB_MANUFACTURER="Unknown"' '-DUSB_PRODUCT="SparkFun Pro Micro"' "-I/home/ashwini/.arduino15/packages/SparkFun/hardware/avr/1.1.6/variants/promicro" "/tmp/arduino_build_569596/sketch/blinky_c_no_serial_for_avrgcc.ino.cpp" -o "/dev/null"

Generating function prototypes...

"/home/ashwini/Downloads/arduino-1.8.3/hardware/tools/avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -flto -w -x c++ -E -CC -mmcu=atmega32u4 -DF_CPU=8000000L -DARDUINO=10803 -DARDUINO_AVR_PROMICRO -DARDUINO_ARCH_AVR -DUSB_VID=0x1b4f -DUSB_PID=0x9204 '-DUSB_MANUFACTURER="Unknown"' '-DUSB_PRODUCT="SparkFun Pro Micro"' "-I/home/ashwini/.arduino15/packages/SparkFun/hardware/avr/1.1.6/variants/promicro" "/tmp/arduino_build_569596/sketch/blinky_c_no_serial_for_avrgcc.ino.cpp" -o "/tmp/arduino_build_569596/preproc/ctags_target_for_gcc_minus_e.cpp"

"/home/ashwini/Downloads/arduino-1.8.3/tools-builder/ctags/5.8-arduino11/ctags" -u --language-force=c++ -f - --c++-kinds=svpf --fields=KSTtzns --line-directives "/tmp/arduino_build_569596/preproc/ctags_target_for_gcc_minus_e.cpp"

Compiling sketch...

"/home/ashwini/Downloads/arduino-1.8.3/hardware/tools/avr/bin/avr-g++" -c -g -Os -Wall -Wextra -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD -flto -mmcu=atmega32u4 -DF_CPU=8000000L -DARDUINO=10803 -DARDUINO_AVR_PROMICRO -DARDUINO_ARCH_AVR -DUSB_VID=0x1b4f -DUSB_PID=0x9204 '-DUSB_MANUFACTURER="Unknown"' '-DUSB_PRODUCT="SparkFun Pro Micro"' "-I/home/ashwini/.arduino15/packages/SparkFun/hardware/avr/1.1.6/variants/promicro" "/tmp/arduino_build_569596/sketch/blinky_c_no_serial_for_avrgcc.ino.cpp" -o "/tmp/arduino_build_569596/sketch/blinky_c_no_serial_for_avrgcc.ino.cpp.o"

Compiling libraries...

Compiling core...

Using precompiled core

Linking everything together...

"/home/ashwini/Downloads/arduino-1.8.3/hardware/tools/avr/bin/avr-gcc" -Wall -Wextra -Os -g -flto -fuse-linker-plugin -Wl,--gc-sections -mmcu=atmega32u4 -o "/tmp/arduino_build_569596/blinky_c_no_serial_for_avrgcc.ino.elf" "/tmp/arduino_build_569596/sketch/blinky_c_no_serial_for_avrgcc.ino.cpp.o" "/tmp/arduino_build_569596/../arduino_cache_732047/core/core_SparkFun_avr_promicro_cpu_8MHzatmega32U4_1e6cbd299ffad185359e932e3440541e.a" "-L/tmp/arduino_build_569596" -lm

"/home/ashwini/Downloads/arduino-1.8.3/hardware/tools/avr/bin/avr-objcopy" -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 "/tmp/arduino_build_569596/blinky_c_no_serial_for_avrgcc.ino.elf" "/tmp/arduino_build_569596/blinky_c_no_serial_for_avrgcc.ino.eep"

"/home/ashwini/Downloads/arduino-1.8.3/hardware/tools/avr/bin/avr-objcopy" -O ihex -R .eeprom "/tmp/arduino_build_569596/blinky_c_no_serial_for_avrgcc.ino.elf" "/tmp/arduino_build_569596/blinky_c_no_serial_for_avrgcc.ino.hex"

Sketch uses 230 bytes (0%) of program storage space. Maximum is 28672 bytes.
Global variables use 0 bytes (0%) of dynamic memory, leaving 2560 bytes for local variables. Maximum is 2560 bytes.

/home/ashwini/Downloads/arduino-1.8.3/hardware/tools/avr/bin/avrdude -C/home/ashwini/.arduino15/packages/SparkFun/hardware/avr/1.1.6/avrdude.conf -v -patmega32u4 -cavr109 -P/dev/ttyACM0 -b57600 -D -Uflash:w:/tmp/arduino_build_569596/blinky_c_no_serial_for_avrgcc.ino.hex:i

These were the set of commands used and yes it seems very daunting, but there is a method to madness that you can parse away, hopefully this will also help people get a better understanding of how to reverse engineer things (even though I am pretty bad at it). The thing to note is that these commands can be directly ran on the Linux command line. The first step for me was to get rid of the everything that depends on ino files and look for files that are c/c++ related (files with endings of c and cpp). The first thing to note is that the first 2 lines convert the into a tmp directory and build a cpp file and those 2 lines are:

home/ashwini/Downloads/arduino-1.8.3/arduino-builder -dump-prefs -logger=machine -hardware /home/ashwini/Downloads/arduino-1.8.3/hardware -hardware /home/ashwini/.arduino15/packages -tools /home/ashwini/Downloads/arduino-1.8.3/tools-builder -tools /home/ashwini/Downloads/arduino-1.8.3/hardware/tools/avr -tools /home/ashwini/.arduino15/packages -built-in-libraries /home/ashwini/Downloads/arduino-1.8.3/libraries -libraries /home/ashwini/Arduino/libraries -fqbn=SparkFun:avr:promicro:cpu=8MHzatmega32U4 -ide-version=10803 -build-path /tmp/arduino_build_569596 -warnings=all -build-cache /tmp/arduino_cache_732047 -prefs=build.warn_data_percentage=75 -verbose /home/ashwini/Arduino/blinky_c_no_serial_for_avrgcc/blinky_c_no_serial_for_avrgcc.ino

/home/ashwini/Downloads/arduino-1.8.3/arduino-builder -compile -logger=machine -hardware /home/ashwini/Downloads/arduino-1.8.3/hardware -hardware /home/ashwini/.arduino15/packages -tools /home/ashwini/Downloads/arduino-1.8.3/tools-builder -tools /home/ashwini/Downloads/arduino-1.8.3/hardware/tools/avr -tools /home/ashwini/.arduino15/packages -built-in-libraries /home/ashwini/Downloads/arduino-1.8.3/libraries -libraries /home/ashwini/Arduino/libraries -fqbn=SparkFun:avr:promicro:cpu=8MHzatmega32U4 -ide-version=10803 -build-path /tmp/arduino_build_569596 -warnings=all -build-cache /tmp/arduino_cache_732047 -prefs=build.warn_data_percentage=75 -verbose /home/ashwini/Arduino/blinky_c_no_serial_for_avrgcc/blinky_c_no_serial_for_avrgcc.ino

I at this point realized that the c/cpp files are stored in

/tmp/arduino_build_569596/sketch/blinky_c_no_serial_for_avrgcc.ino.cpp

because it is the same name as ino file also. I then removed the first 2 lines and commented out lines for generating function prototypes just to see what it would do and it seemed to have no impact on the build process. Note: Right before running the avrdude command to upload I had to always reset the MCU in order for the upload to be successful. In order to make sure I was doing everything right, I would first use the led blinking script to make sure things are working and then just compile the script that doesn’t have any dependency on Arduino and then try to upload everything one line at a time on the cmdline. So the new script now became:

 

#removed all the dependency of the arduino core libraries and removed all appearance of ino files, even though ino files have not been removed

"/home/ashwini/Downloads/arduino-1.8.3/hardware/tools/avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -flto -w -x c++ -E -CC -mmcu=atmega32u4 -DF_CPU=8000000L -DARDUINO=10803 -DARDUINO_AVR_PROMICRO -DARDUINO_ARCH_AVR -DUSB_VID=0x1b4f -DUSB_PID=0x9204 '-DUSB_MANUFACTURER="Unknown"' '-DUSB_PRODUCT="SparkFun Pro Micro"' "-I/home/ashwini/.arduino15/packages/SparkFun/hardware/avr/1.1.6/variants/promicro" "/tmp/arduino_build_569596/sketch/blinky_c_no_serial_for_avrgcc.ino.cpp" -o "/dev/null"

#Generating function prototypes...

#"/home/ashwini/Downloads/arduino-1.8.3/hardware/tools/avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -flto -w -x c++ -E -CC -mmcu=atmega32u4 -DF_CPU=8000000L -DARDUINO=10803 -DARDUINO_AVR_PROMICRO -DARDUINO_ARCH_AVR -DUSB_VID=0x1b4f -DUSB_PID=0x9204 '-DUSB_MANUFACTURER="Unknown"' '-DUSB_PRODUCT="SparkFun Pro Micro"' "-I/home/ashwini/.arduino15/packages/SparkFun/hardware/avr/1.1.6/variants/promicro" "/tmp/arduino_build_569596/sketch/blinky_c_no_serial_for_avrgcc.ino.cpp" -o "/tmp/arduino_build_569596/preproc/ctags_target_for_gcc_minus_e.cpp"

#"/home/ashwini/Downloads/arduino-1.8.3/tools-builder/ctags/5.8-arduino11/ctags" -u --language-force=c++ -f - --c++-kinds=svpf --fields=KSTtzns --line-directives "/tmp/arduino_build_569596/preproc/ctags_target_for_gcc_minus_e.cpp"

#Compiling sketch...

"/home/ashwini/Downloads/arduino-1.8.3/hardware/tools/avr/bin/avr-g++" -c -g -Os -Wall -Wextra -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD -flto -mmcu=atmega32u4 -DF_CPU=8000000L -DARDUINO=10803 -DARDUINO_AVR_PROMICRO -DARDUINO_ARCH_AVR -DUSB_VID=0x1b4f -DUSB_PID=0x9204 '-DUSB_MANUFACTURER="Unknown"' '-DUSB_PRODUCT="SparkFun Pro Micro"' "-I/home/ashwini/.arduino15/packages/SparkFun/hardware/avr/1.1.6/variants/promicro" "/tmp/arduino_build_569596/sketch/blinky_c_no_serial_for_avrgcc.ino.cpp" -o "/tmp/arduino_build_569596/sketch/blinky_c_no_serial_for_avrgcc.ino.cpp.o"

#Compiling libraries...

#Compiling core...

#Using precompiled core

#Linking everything together...

"/home/ashwini/Downloads/arduino-1.8.3/hardware/tools/avr/bin/avr-gcc" -Wall -Wextra -Os -g -flto -fuse-linker-plugin -Wl,--gc-sections -mmcu=atmega32u4 -o "/tmp/arduino_build_569596/blinky_c_no_serial_for_avrgcc.ino.elf" "/tmp/arduino_build_569596/sketch/blinky_c_no_serial_for_avrgcc.ino.cpp.o" "/tmp/arduino_build_569596/../arduino_cache_732047/core/core_SparkFun_avr_promicro_cpu_8MHzatmega32U4_1e6cbd299ffad185359e932e3440541e.a" "-L/tmp/arduino_build_569596" -lm

"/home/ashwini/Downloads/arduino-1.8.3/hardware/tools/avr/bin/avr-objcopy" -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 "/tmp/arduino_build_569596/blinky_c_no_serial_for_avrgcc.ino.elf" "/tmp/arduino_build_569596/blinky_c_no_serial_for_avrgcc.ino.eep"

"/home/ashwini/Downloads/arduino-1.8.3/hardware/tools/avr/bin/avr-objcopy" -O ihex -R .eeprom "/tmp/arduino_build_569596/blinky_c_no_serial_for_avrgcc.ino.elf" "/tmp/arduino_build_569596/blinky_c_no_serial_for_avrgcc.ino.hex"

#Sketch uses 230 bytes (0%) of program storage space. Maximum is 28672 bytes.
#Global variables use 0 bytes (0%) of dynamic memory, leaving 2560 bytes for local variables. Maximum is 2560 bytes.

/home/ashwini/Downloads/arduino-1.8.3/hardware/tools/avr/bin/avrdude -C/home/ashwini/.arduino15/packages/SparkFun/hardware/avr/1.1.6/avrdude.conf -v -patmega32u4 -cavr109 -P/dev/ttyACM0 -b57600 -D -Uflash:w:/tmp/arduino_build_569596/blinky_c_no_serial_for_avrgcc.ino.hex:i

#this still turns out to be succesfull

As you can see the ino depedency is gone. The ‘#’ in these scripts represent a comment. I played around with the ctags but that seemed to very little impact on my code so I removed all ctags information with the following command:

rm /tmp/arduino_build_569596/preproc/ctags_target_for_gcc_minus_e.cpp

and it didn’t seem to have a large impact. The next step was to completely remove all notion of using tmp files and copy the c file that I created which I wrote as an ino file and move it to my git repo so I could play with the file. The file I created was called led.c (yea I know I am using confusing nomenclature, but at after a certain point at night everything starts to blur together). The next code got rid of all dependency on the tmp directory and it looked like this

#replacing all tmp directory calls to be in the git repo
"/home/ashwini/Downloads/arduino-1.8.3/hardware/tools/avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -flto -w -x c++ -E -CC -mmcu=atmega32u4 -DF_CPU=8000000L -DARDUINO=10803 -DARDUINO_AVR_PROMICRO -DARDUINO_ARCH_AVR -DUSB_VID=0x1b4f -DUSB_PID=0x9204 '-DUSB_MANUFACTURER="Unknown"' '-DUSB_PRODUCT="SparkFun Pro Micro"' "-I/home/ashwini/.arduino15/packages/SparkFun/hardware/avr/1.1.6/variants/promicro" "/home/ashwini/git-repos/arduino/led_blink_without_arduino_ide/led.cpp" -o "/dev/null"

#Generating function prototypes...

#"/home/ashwini/Downloads/arduino-1.8.3/hardware/tools/avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -flto -w -x c++ -E -CC -mmcu=atmega32u4 -DF_CPU=8000000L -DARDUINO=10803 -DARDUINO_AVR_PROMICRO -DARDUINO_ARCH_AVR -DUSB_VID=0x1b4f -DUSB_PID=0x9204 '-DUSB_MANUFACTURER="Unknown"' '-DUSB_PRODUCT="SparkFun Pro Micro"' "-I/home/ashwini/.arduino15/packages/SparkFun/hardware/avr/1.1.6/variants/promicro" "/tmp/arduino_build_569596/sketch/blinky_c_no_serial_for_avrgcc.ino.cpp" -o "/tmp/arduino_build_569596/preproc/ctags_target_for_gcc_minus_e.cpp"

#"/home/ashwini/Downloads/arduino-1.8.3/tools-builder/ctags/5.8-arduino11/ctags" -u --language-force=c++ -f - --c++-kinds=svpf --fields=KSTtzns --line-directives "/tmp/arduino_build_569596/preproc/ctags_target_for_gcc_minus_e.cpp"

rm /tmp/arduino_build_569596/preproc/ctags_target_for_gcc_minus_e.cpp

#Compiling sketch...

"/home/ashwini/Downloads/arduino-1.8.3/hardware/tools/avr/bin/avr-g++" -c -g -Os -Wall -Wextra -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD -flto -mmcu=atmega32u4 -DF_CPU=8000000L -DARDUINO=10803 -DARDUINO_AVR_PROMICRO -DARDUINO_ARCH_AVR -DUSB_VID=0x1b4f -DUSB_PID=0x9204 '-DUSB_MANUFACTURER="Unknown"' '-DUSB_PRODUCT="SparkFun Pro Micro"' "-I/home/ashwini/.arduino15/packages/SparkFun/hardware/avr/1.1.6/variants/promicro" "/home/ashwini/git-repos/arduino/led_blink_without_arduino_ide/led.cpp" -o "/home/ashwini/git-repos/arduino/led_blink_without_arduino_ide/led.cpp.o"




#Compiling libraries...

#Compiling core...

#Using precompiled core

#Linking everything together...

rm /tmp/arduino_build_569596/../arduino_cache_732047/core/core_SparkFun_avr_promicro_cpu_8MHzatmega32U4_1e6cbd299ffad185359e932e3440541e.a

"/home/ashwini/Downloads/arduino-1.8.3/hardware/tools/avr/bin/avr-gcc" -Wall -Wextra -Os -g -flto -fuse-linker-plugin -Wl,--gc-sections -mmcu=atmega32u4 -o "/home/ashwini/git-repos/arduino/led_blink_without_arduino_ide/led.elf" "/home/ashwini/git-repos/arduino/led_blink_without_arduino_ide/led.cpp.o" "-L/home/ashwini/git-repos/arduino/led_blink_without_arduino_ide" -lm

"/home/ashwini/Downloads/arduino-1.8.3/hardware/tools/avr/bin/avr-objcopy" -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 "/home/ashwini/git-repos/arduino/led_blink_without_arduino_ide/led.elf" "/home/ashwini/git-repos/arduino/led_blink_without_arduino_ide/led.eep"

"/home/ashwini/Downloads/arduino-1.8.3/hardware/tools/avr/bin/avr-objcopy" -O ihex -R .eeprom "/home/ashwini/git-repos/arduino/led_blink_without_arduino_ide/led.elf" "/home/ashwini/git-repos/arduino/led_blink_without_arduino_ide/led.hex"

#Sketch uses 230 bytes (0%) of program storage space. Maximum is 28672 bytes.
#Global variables use 0 bytes (0%) of dynamic memory, leaving 2560 bytes for local variables. Maximum is 2560 bytes.

read -p "Reset the sparkfun micro and then press any key to flash the arduino"

/home/ashwini/Downloads/arduino-1.8.3/hardware/tools/avr/bin/avrdude -C/home/ashwini/.arduino15/packages/SparkFun/hardware/avr/1.1.6/avrdude.conf -v -patmega32u4 -cavr109 -P/dev/ttyACM0 -b57600 -D -Uflash:w:/home/ashwini/git-repos/arduino/led_blink_without_arduino_ide/led.hex:i

#this works also I was able to replace all the extra calls to the tmp directory and do it all in c

This was the biggest clue I was going down the right path, because I used a file called led.c:

#include <avr/io.h>
#include <util/delay.h>

#define BLINK_DELAY_MS 100

int main(void);
int main (void)
{
 /* set pin 5 of PORTB for output*/
 (*(volatile unsigned int*)(0x24)) |= (1<<(5));

while(1) {
 /* set pin 5 high to turn led on */
 (*(volatile unsigned int*)(0x25)) |= (1<<(5));

/* set pin 5 low to turn led off */
 (*(volatile unsigned int*)(0x25)) &= (0<<(5));
 }
}

and since this worked I knew everything was on the right path and remember I always verify by going back to a known state which is using the scrip that blinks to LEDs using the arduino and then I can always come back to toggling the PB5  when I upload my code so that really helped. The next step was to remove all commands being executed from the arduino directory and use the base avr-gcc available on my linux computer and the script was:

#replacing all tmp directory calls to be in the git repo
avr-gcc -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -flto -w -mmcu=atmega32u4 -DF_CPU=8000000L -DARDUINO=10803 -DARDUINO_AVR_PROMICRO -DARDUINO_ARCH_AVR -DUSB_VID=0x1b4f -DUSB_PID=0x9204 '-DUSB_MANUFACTURER="Unknown"' '-DUSB_PRODUCT="SparkFun Pro Micro"' "-I/home/ashwini/.arduino15/packages/SparkFun/hardware/avr/1.1.6/variants/promicro" "/home/ashwini/git-repos/arduino/led_blink_without_arduino_ide/led.c" -o "/home/ashwini/git-repos/arduino/led_blink_without_arduino_ide/log.txt"

#Compiling sketch...

avr-gcc -c -g -Os -Wall -Wextra -fno-exceptions -ffunction-sections -fdata-sections -MMD -flto -mmcu=atmega32u4 -DF_CPU=8000000L -DARDUINO=10803 -DARDUINO_AVR_PROMICRO -DARDUINO_ARCH_AVR -DUSB_VID=0x1b4f -DUSB_PID=0x9204 '-DUSB_MANUFACTURER="Unknown"' '-DUSB_PRODUCT="SparkFun Pro Micro"' "-I/home/ashwini/.arduino15/packages/SparkFun/hardware/avr/1.1.6/variants/promicro" "/home/ashwini/git-repos/arduino/led_blink_without_arduino_ide/led.c" -o "/home/ashwini/git-repos/arduino/led_blink_without_arduino_ide/led.o"




#Compiling libraries...

#Compiling core...

#Using precompiled core

#Linking everything together...

avr-gcc -Wall -Wextra -Os -g -flto -fuse-linker-plugin -Wl,--gc-sections -mmcu=atmega32u4 -o "/home/ashwini/git-repos/arduino/led_blink_without_arduino_ide/led.elf" "/home/ashwini/git-repos/arduino/led_blink_without_arduino_ide/led.o" "-L/home/ashwini/git-repos/arduino/led_blink_without_arduino_ide" -lm

avr-objcopy -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 "/home/ashwini/git-repos/arduino/led_blink_without_arduino_ide/led.elf" "/home/ashwini/git-repos/arduino/led_blink_without_arduino_ide/led.eep"

avr-objcopy -O ihex -R .eeprom "/home/ashwini/git-repos/arduino/led_blink_without_arduino_ide/led.elf" "/home/ashwini/git-repos/arduino/led_blink_without_arduino_ide/led.hex"

#Sketch uses 230 bytes (0%) of program storage space. Maximum is 28672 bytes.
#Global variables use 0 bytes (0%) of dynamic memory, leaving 2560 bytes for local variables. Maximum is 2560 bytes.

read -p "Reset the sparkfun micro and then press any key to flash the arduino"

avrdude -C/home/ashwini/.arduino15/packages/SparkFun/hardware/avr/1.1.6/avrdude.conf -v -patmega32u4 -cavr109 -P/dev/ttyACM0 -b57600 -D -Uflash:w:/home/ashwini/git-repos/arduino/led_blink_without_arduino_ide/led.hex:i

#this works also I was able to replace all the extra calls to the tmp directory and do it all in c, removed all c++ specific flags. Now removed all the arduino specific gcc calls and now using system avr-gcc and avr-objcopy and avrdude

The read part I have before avr dude allows me to reset the pro micro before I flash it using avr dude. I completely removed all arduino related dependency.  I still do need to point to the ProMicro configuration file in order to use the header files that are available and to properly upload the executable file.  This allowed me to completely run without the arduino IDE. The next step is to figure out how all the functions work. I looked in ELF (Executable and Linkable Format) files which are extremely useful in these conversations and i found this link and this link, which were extremely useful in explaining how an elf file is created and made. This link was also useful. I was still in the process of decoupling all the flags but

-ffunction-sections -fdata-sections

are used so that every function I create get goes in a seperate section and each piece of data gets a seperate section. The -D flag are macros, which can also be set in a #define as shown in this link. Here is another link that explain those compiler optimizations.

UPDATE:

As I was playing around I have noticed that the manual version that I created to compile and upload the to sparkfun causes an issue.  The reason for this because the arduino has a main.ccp file which runs code called USBDevice.attach() which is relevant for arduino leonard (or the sparkfun pro micro for that matter). This is important because it allows the usb device to stay attached after the hex file is uploaded to mcu. If this is not in your file I saw /dev/ttyACM0 get attached for 5-15 secs and then you see the device disappear. There is a usb attach function that keeps it attached but for now I think that will be too confusing for me so I have decided to switch to Arduino uno to make my life a little easier. I will let you know when I come back to sparkfun pro micro.

As always here is the link to the github.

Here is my list of useful links:

https://arduino.stackexchange.com/questions/9064/trying-to-track-down-macro-or-define-values-possibly-in-arduino-preprocessor

https://balau82.wordpress.com/2011/03/29/programming-arduino-uno-in-pure-c/

http://www.nongnu.org/avrdude/user-manual/avrdude_10.htmlhttps://www.arduino.cc/en/Hacking/Bootloader

https://github.com/arduino/Arduino/wiki/Build-Process

https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5-3rd-party-Hardware-specification

https://github.com/arduino/Arduino/wiki/Arduino-Hardware-Cores-migration-guide-from-1.0-to-1.6

https://forum.arduino.cc/index.php?topic=158701.0

https://www.mankier.com/1/arduino-ctagshttps://stackoverflow.com/questions/20177113/how-to-disable-gcc-warning-cc1-warning-command-line-option-std-c11-is-va

https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#Optimize-Options

https://arduino.stackexchange.com/questions/9064/trying-to-track-down-macro-or-define-values-possibly-in-arduino-preprocessor

https://groups.google.com/forum/#!topic/fa.freebsd.current/RUZnbnYykQo

ELF information:

http://www.linuxjournal.com/article/1059?page=0,1

http://www.cirosantilli.com/elf-hello-world/

http://www.linuxjournal.com/article/1060

https://linux-audit.com/elf-binaries-on-linux-understanding-and-analysis/https://groups.google.com/forum/#!topic/fa.freebsd.current/RUZnbnYykQo

 

 

 

 

Timers and PWM on SparkFun Pro Micro

So this will be a short one. Basically the goal here is use the TIMER to make a PWM.  It builds on the post.  The main thing that I changed now is that instead of having the ISR I let the hardware do all the timing work. The website that really helped me was a post by Vicente and as always the documentation for ATMega32U4.

Remember the Pro Micro and the Leonards use the same processor and all I had to do was look at the hardware schematics to see which pin the processor was outputting to (schematic file found here).  Since most of the information is found in Vicente’s post I don’t want re post all the images he found. I will however walk through my code.

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>




//setting up TCCR1A control register
unsigned char COM1A1_val = 0b10000000;
unsigned char COM1A0_val = 0b01000000;
unsigned char COM1B1_val = 0b00100000;
unsigned char COM1B0_val = 0b00010000;
unsigned char COM1C1_val = 0b00001000;
unsigned char COM1C0_val = 0b00000100;
unsigned char WGM11_val = 0b00000010;
unsigned char WGM10_val = 0b00000001;

//setting up TCCR1B control register
unsigned char ICNC1_val = 0b10000000;
unsigned char ICES1_val = 0b01000000;
unsigned char WGM13_val = 0b00010000;
unsigned char WGM12_val = 0b00001000;
unsigned char CS12_val = 0b00000100;
unsigned char CS11_val = 0b00000010;
unsigned char CS10_val = 0b00000001;







//Register variables

unsigned char OCR1AL_reg = 0x88; //output compare low 8 bits for Counter 1
unsigned char OCR1AH_reg = 0x89; //output compare high 8 bits for Counter 1

unsigned char TCCR1B_reg = 0x81; //Timer/Counter0 Control Register B 
unsigned char TCCR1A_reg = 0x80; //Timer/Counter0 Control Register A

unsigned char TIMSK1_reg = 0x6F; //Timer/Counter0 Interrupt Mask Register

unsigned char TIFR1_reg = 0x36; //Timer/Counter0 Interrupt Flag Register

unsigned char TCNT1H_reg = 0x85; //Timer/Counter0 Interrupt Flag Register
unsigned char TCNT1L_reg = 0x84; //Timer/Counter0 Interrupt Flag Register

//setting up PB5
unsigned char DDRB_reg = 0x24; //Sets up the DDR for Bank 5
unsigned char PORTB_reg = 0x25; //sets up port B
unsigned char PINB_reg = 0x23; //to be able to read PINB5

unsigned char SREG_reg = 0x5F; //Status register used for disabling and enabling global interrupts

int stopeverything = 0;

void setup()
{

Serial.begin(9600); //This pipes to the serial monitor

//setting up PB5
 (*(volatile unsigned char *)(DDRB_reg)) = 0b00100000;
 (*(volatile unsigned char *)(PORTB_reg)) = 0b00100000;

//resetting the Timer/Counter1
 (*(volatile unsigned char*)(TCNT1H_reg)) = 0;
 (*(volatile unsigned char*)(TCNT1L_reg)) = 0; 
 
 //disabling all global interrupts
 (*(volatile unsigned char *)(SREG_reg)) = 0b00000000;

//defining prescalar
 //(*(volatile unsigned char *)(TCCR1B_reg)) = ICES1_val|WGM13_val|WGM12_val|CS12_val|CS10_val;//0b01001101; //the last 3 bits set to 101 will make the clock scalar 1024;
 //(*(volatile unsigned char *)(TCCR1B_reg)) = ICES1_val|CS12_val;//0b01001101; //the last 3 bits set to 101 will make the clock scalar 1;
 (*(volatile unsigned char *)(TCCR1B_reg)) = 0;
 (*(volatile unsigned char *)(TCCR1B_reg)) = CS11_val;

//setting up PWM mode
 (*(volatile unsigned char *)(TCCR1A_reg)) = 0; //this is for waveform generation and CTC setting up mode;
 (*(volatile unsigned char *)(TCCR1A_reg)) = COM1A1_val|WGM10_val; //this is for waveform generation and CTC setting up mode;

//defining the output compare value which is calculated to be 3906 assuming 8MHz clock speed: OCRNA = (fClk_I/O)/(2*N*fOCRNA) where N is the prescalar fOCRNA is the compare value and fClk_I/O is the clock speed
 //the value calculated for fOCRNA to be 1Hz is ~3096
 (*(volatile unsigned char *)(OCR1AH_reg)) = 0b00001111; //writing to high first which will write to a temp register first
 (*(volatile unsigned char *)(OCR1AL_reg)) = 0b01000010; //writing to low will write both high and low in the same clock cycle

//using output value of 300
 
 //(*(volatile unsigned char *)(OCR1AH_reg)) = 0b00000001; //writing to high first which will write to a temp register first
 //(*(volatile unsigned char *)(OCR1AL_reg)) = 0b00000100; //writing to low will write both high and low in the same clock cycle

//using compare value of 30
 
 //(*(volatile unsigned char *)(OCR1AH_reg)) = 0b00000000; //writing to high first which will write to a temp register first
 //(*(volatile unsigned char *)(OCR1AL_reg)) = 0b00000110; //writing to low will write both high and low in the same clock cycle
 
 //using compare value of 1
 
 //(*(volatile unsigned char *)(OCR1AH_reg)) = 0b00000000; //writing to high first which will write to a temp register first
 //(*(volatile unsigned char *)(OCR1AL_reg)) = 0b00000001; //writing to low will write both high and low in the same clock cycle




(*(volatile unsigned char *)(TIMSK1_reg)) = 0;//0b00100010; //writing so that output compare A is set up




//enable global interrupts
 (*(volatile unsigned char *)(SREG_reg)) = 0b10000000;







}

/*ISR(TIMER1_COMPA_vect) // timer compare interrupt service routine
{
 //(*(volatile unsigned char *)(PORTB_reg)) = (*(volatile unsigned char *)(PORTB_reg)) ^ (1<<5);
 Serial.println("interrupt!");
 stopeverything=1;
}*/




void loop()
{
 //Serial.println(
 // (*(volatile unsigned char*)TCNT1H_reg << 8) | (*(volatile unsigned char*)TCNT1L_reg),BIN);
 //Serial.println("");
 //if(stopeverything==1){
 //Serial.println("Coming from interrupt!!");
 //delay(2000);
 //stopeverything=0;
 //}
}

 

Let’s start from the top:

//Register variables

unsigned char OCR1AL_reg = 0x88; //output compare low 8 bits for Counter 1
unsigned char OCR1AH_reg = 0x89; //output compare high 8 bits for Counter 1

unsigned char TCCR1B_reg = 0x81; //Timer/Counter0 Control Register B 
unsigned char TCCR1A_reg = 0x80; //Timer/Counter0 Control Register A

unsigned char TIMSK1_reg = 0x6F; //Timer/Counter0 Interrupt Mask Register

unsigned char TIFR1_reg = 0x36; //Timer/Counter0 Interrupt Flag Register

unsigned char TCNT1H_reg = 0x85; //Timer/Counter0 Interrupt Flag Register
unsigned char TCNT1L_reg = 0x84; //Timer/Counter0 Interrupt Flag Register

//setting up PB5
unsigned char DDRB_reg = 0x24; //Sets up the DDR for Bank 5
unsigned char PORTB_reg = 0x25; //sets up port B
unsigned char PINB_reg = 0x23; //to be able to read PINB5

unsigned char SREG_reg = 0x5F; //Status register used for disabling and enabling global interrupts

int stopeverything = 0;

 

My first step was declaring assigning values for the different bits but before we do I want to skip ahead and I assigned all the address as my own variables so I could use them later on. The stopeverything variables does nothing, it is a hold over from my last post.  So I would just ignore it.  All I am doing is asigning all the address and placing them into variables so that I can understand what is going on. There are 2 control registers TCCR1B and TCCR1A which are used for setting the clock prescalar and if you want a PWM output or not. All of this information I found on this page 408-411 on ATMega32U4 datasheet.

Then I assigned variables for each bit that was necessary in order for me to make it easier to work with them instead of trying to count out bits like I have been doing previously.

//setting up TCCR1A control register
unsigned char COM1A1_val = 0b10000000;
unsigned char COM1A0_val = 0b01000000;
unsigned char COM1B1_val = 0b00100000;
unsigned char COM1B0_val = 0b00010000;
unsigned char COM1C1_val = 0b00001000;
unsigned char COM1C0_val = 0b00000100;
unsigned char WGM11_val = 0b00000010;
unsigned char WGM10_val = 0b00000001;

//setting up TCCR1B control register
unsigned char ICNC1_val = 0b10000000;
unsigned char ICES1_val = 0b01000000;
unsigned char WGM13_val = 0b00010000;
unsigned char WGM12_val = 0b00001000;
unsigned char CS12_val = 0b00000100;
unsigned char CS11_val = 0b00000010;
unsigned char CS10_val = 0b00000001;

The information can be found on p.129-133 in the data sheet and you can see I am just setting one bit, but the point of it is so that I can “OR” them together using the “|”.  This allows me to do things like WGM13_val|WGM12_val which is does this operation of 0b00010000 | 0b00001000 = 0b00011000 and this allows me to to not use binary but use the variable name instead and that is much easier to handle when setting up the registers and prescalars.

As  you can see that the bits are called from this table and its too hard to keep track of the bits.  The images are all from Vicente’s website.

The next step is very similar to last time but the big difference is that now I have to set up PB5 to output so that the timer can toggle it up and down.

//setting up PB5
 (*(volatile unsigned char *)(DDRB_reg)) = 0b00100000;
 (*(volatile unsigned char *)(PORTB_reg)) = 0b00100000;

//resetting the Timer/Counter1
 (*(volatile unsigned char*)(TCNT1H_reg)) = 0;
 (*(volatile unsigned char*)(TCNT1L_reg)) = 0; 
 
 //disabling all global interrupts
 (*(volatile unsigned char *)(SREG_reg)) = 0b00000000;

//defining prescalar
 //(*(volatile unsigned char *)(TCCR1B_reg)) = ICES1_val|WGM13_val|WGM12_val|CS12_val|CS10_val;//0b01001101; //the last 3 bits set to 101 will make the clock scalar 1024;
 //(*(volatile unsigned char *)(TCCR1B_reg)) = ICES1_val|CS12_val;//0b01001101; //the last 3 bits set to 101 will make the clock scalar 1;
 (*(volatile unsigned char *)(TCCR1B_reg)) = 0;
 (*(volatile unsigned char *)(TCCR1B_reg)) = CS11_val;

//setting up PWM mode
 (*(volatile unsigned char *)(TCCR1A_reg)) = 0; //this is for waveform generation and CTC setting up mode;
 (*(volatile unsigned char *)(TCCR1A_reg)) = COM1A1_val|WGM10_val; 
//this is for waveform generation and CTC setting up mode;
 (*(volatile unsigned char *)(OCR1AH_reg)) = 0b00001111; //writing to high first which will write to a temp register first
 (*(volatile unsigned char *)(OCR1AL_reg)) = 0b01000010; //writing to low will write both high and low in the same clock cycle

(*(volatile unsigned char *)(TIMSK1_reg)) = 0;//0b00100010; //writing so that output compare A is set up

//enable global interrupts
 (*(volatile unsigned char *)(SREG_reg)) = 0b10000000;

And you can see that first I set PB5 to output by first setting the DDR and then the PORTB5 pin.  I reset the counters to 0, then remove all global interrupts so I don’t get interrupts while the code is trying to execute.  Set up a prescalar and you will notice I first set both TCCR1B and TCCR1A to 0 because I ran into issues because of the “|” operation it kept saving all the bits from last time causing nothing to happen.  I then set the prescalar to be 8 (CS11_val = CSn1 from table) and set the timer to compare the A register and used the WGM10_val to set a version of the PWM.  The next step was to all ISRs by setting the TIMSK1_reg to 0.  Then I enabled all the interrupts and then voila I had a PWM when I scoped Pin 9 on the ProMicro.  As I changed the value of OCR1A I change the PWM duty cycle and with prescalar I change the duration.

As always here are my useful links:

http://www.catonmat.net/blog/low-level-bit-hacks-you-absolutely-must-know/

https://stackoverflow.com/questions/14526584/what-does-the-xor-operator-do

http://r6500.blogspot.com/2014/12/fast-pwm-on-arduino-leonardo.html

Please feel free to ask me and stuff can be found on my github!

 

Timers and Interrupts on SparkFun ProMicro

So last time I talked about blinking an LED directly from using the registers. Now I will move on to something a bit more complicated. Not everything is working quite right but I know I am headed in the right direction. This time around I am using a timer that will count to a certain value and then create an interrupt and then reset from the top. Again I am using this board.

The main goal of this exercise will be to work with a timer on the arduino and when a certain time is reached, the counter stop, does something and then restarts from the beginning. I have not converted completely to C code but I am accessing the registers directly. Most of the work I did was done on Timer1, I tried messing around with Timer0 but it became apparent that I should stay away from it, mainly because arduino’s built in functionality uses Timer0.

Timer0 is an 8 bit timer and Timer1 is a 16bit timer.

In order to first get started we to understand timers.  I have one way the timer can work (timers can run in multiple different modes, but we will look at one that is close to ours):

Screenshot from 2017-07-12 23:06:58

Figure 1 (image found here)

So let’s start with nomenclature:

  1. TCNTnH: Counter register high byte for Timer n. Ex: TCNT1H is the counter register high byte for Timer1.
  2. TCNTnL: Counter register low byte for Timer n. Ex: TCNT1L is the counter register low byte for Timer1.
  3. OCRnxH: Output compare register A high byte for timer n. OCR1AH is the output compare register A high byte for timer 1.
  4. OCRnxL: Output compare register A low byte for timer n. OCR1AL is the output compare register A low byte for timer 1.
  5. OCFnX: Output Compare flag for X on timer X.  OCF1A sets up a flag that lets the MCU know that TCNT1 will be compared with OCR1A. This is set up by the TIFRn register, also known as Timer Interrupt Flag Register.

TCNT1 is the timer/counter that is counting and as soon as TCNT1 hits the value specified in OCR1A OCF1A goes high until the interrupt corresponding to the flag is executed (this can result in setting another pin high or in our case printing out to the serial monitor.)  Don’t worry about the Waveform Generator and OCnx for this explanation.  The other major take away is that the OCRnx is divided into high and low bytes and so are TCNTn. So when you try to write TCNTnH you will always write to a temp register first and when you write to TCNTnL directly will TCNTnH be written to from the temp register.  The same thing is happening in OCRnx. Just a side note I don’t know why there are multiple compare registers, but my best guess is that they can be used for different things and compare at different times.

So then how is TCNT1 is counting? The following is shown in the image below:

Screenshot from 2017-07-12 23:26:00

Figure 2 (image found here)

So how does the counting occur.  We can select the clock source (Tn) we want, we can have an external clock source or an internal clock source (the clock provided by your MCU). On top that there is a concept of prescalar.  This concept simply allows you to choose longer units of time (output clock time is defined by clkTn). Let’s take for example the internal clock which runs at 8MHz. This means if you have a 16bit counter (can count up to 2^16=65535), your maximum time available before an interrupt is generated is ~8ms. So the clock will be counting at 8MHz and will go back to 0 as soon as TCNTn will hit 65536. What if you want to wait for longer? The solution is prescalar. What if we counted every 2 cycles as one or every 4 cycles as one we could spread out the time it takes to count. Let’s take an example when the prescalar is 2.  This will effective make the counter move at 4MHz which will cause the counter to max out at ~16MHz (((1/4000000)*65536)*1000, multiplied by a 1000 to get to ms).  So we set the counting rate by prescalar which impacts how quickly TCNTn will count and that is then compared to OCRnX.  I do want to warn you that I am talking about a specific mode that I am using the timer in, the timer can be used for also generating PWMs which I am not getting into it now, but we can choose those settings based on WGMn3:0, COMn1:0. As we move forward you will see me set those settings in order to work under the CTC mode (non-pwm mode).

But before you do everything you have disable the global interrupts in order to make sure that interrupts don’t get created while you are trying to set up the OCR registers and TCNTn register.

To summarize: disable the global interrupt –> define the clock source and pre scalar –> set up the mode you want to run in (PWM, CTC, etc, this is found in p130-132 in the datasheet) –> set up output compare register –> in order to use the output compare register (A, B, or C) we have to setup the TIMSKx (Timer1 Interrupt Mask Register) which will tell the processor to look for which Output compare to use –> re-enable the global interrupt –> do other things now.

Here is the raw code:

/* Pro Micro Test Code
 by: Nathan Seidle
 modified by: Jim Lindblom
 SparkFun Electronics
 date: September 16, 2013
 license: Public Domain - please use this code however you'd like.
 It's provided as a learning tool.

This code is provided to show how to control the SparkFun
 ProMicro's TX and RX LEDs within a sketch. It also serves
 to explain the difference between Serial.print() and
 Serial1.print().
*/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>




//Register variables

unsigned char OCR1AL_reg = 0x88; //output compare low 8 bits for Counter 1
unsigned char OCR1AH_reg = 0x89; //output compare high 8 bits for Counter 1

unsigned char TCCR1B_reg = 0x81; //Timer/Counter0 Control Register B 
unsigned char TCCR1A_reg = 0x80; //Timer/Counter0 Control Register A

unsigned char TIMSK1_reg = 0x6F; //Timer/Counter0 Interrupt Mask Register

unsigned char TIFR1_reg = 0x36; //Timer/Counter0 Interrupt Flag Register

unsigned char TCNT1H_reg = 0x85; //Timer/Counter0 Interrupt Flag Register
unsigned char TCNT1L_reg = 0x84; //Timer/Counter0 Interrupt Flag Register




unsigned char SREG_reg = 0x5F; //Status register used for disabling and enabling global interrupts

int stopeverything = 0;

void setup()
{

Serial.begin(9600); //This pipes to the serial monitor

//resetting the Timer/Counter1
 (*(volatile unsigned char*)(TCNT1H_reg)) = 0;
 (*(volatile unsigned char*)(TCNT1L_reg)) = 0; 
 
 //disabling all global interrupts
 (*(volatile unsigned char *)(SREG_reg)) = 0b00000000;

//defining prescalar
 (*(volatile unsigned char *)(TCCR1B_reg)) = 0b01001101; //the last 3 bits set to 101 will make the clock scalar 1024;
 //setting up CTC mode
 (*(volatile unsigned char *)(TCCR1A_reg)) = 0b10000000; //the last 3 bits set to 101 will make the clock scalar 1024;

//defining the output compare value which is calculated to be 3906 assuming 8MHz clock speed: OCRNA = (fClk_I/O)/(2*N*fOCRNA) where N is the prescalar fOCRNA is the compare value and fClk_I/O is the clock speed
 //the value calculated for fOCRNA to be 1Hz is ~3096
 //(*(volatile unsigned char *)(OCR1AH_reg)) = 0b00001111; //writing to high first which will write to a temp register first
 //(*(volatile unsigned char *)(OCR1AL_reg)) = 0b01000010; //writing to low will write both high and low in the same clock cycle

//defining the output compare value which is calculated to be 3906 assuming 8MHz clock speed: OCRNA = (fClk_I/O)/(2*N*fOCRNA) where N is the prescalar fOCRNA is the compare value and fClk_I/O is the clock speed
 //the value calculated for fOCRNA to be 0.1Hz is ~30960
 (*(volatile unsigned char *)(OCR1AH_reg)) = 0b11110001; //writing to high first which will write to a temp register first
 //(*(volatile unsigned char *)(OCR1AH_reg)) = 0b11111111; //writing to high first which will write to a temp register first
 (*(volatile unsigned char *)(OCR1AL_reg)) = 0b11100000; //writing to low will write both high and low in the same clock cycle
 //(*(volatile unsigned char *)(OCR1AL_reg)) = 0b11111111; //writing to low will write both high and low in the same clock cycle




(*(volatile unsigned char *)(TIMSK1_reg)) = 0b00100010; //writing so that output compare A is set up

//enable global interrupts
 (*(volatile unsigned char*)(SREG_reg)) = 0b10000000;







}

ISR(TIMER1_COMPA_vect) // timer compare interrupt service routine
{
 Serial.println("interrupt!");
 stopeverything=1;
}




void loop()
{
 Serial.println(
 (*(volatile unsigned char*)TCNT1H_reg << 8) | (*(volatile unsigned char*)TCNT1L_reg),BIN);
 //Serial.println("");
 if(stopeverything==1){
 Serial.println("Coming from interrupt!!");
 delay(2000);
 stopeverything=0;
 }
}

Just look at the stuff that I doesn’t have “//” in front of it. I found all the registers address on 408-411 in the data sheet.  I define all the registers address above setup() and then in the setup function I set the value for each of registers be dereferencing the pointers associated with the variables (you might get warning while compiling it but ignore it).  Remember SREG is the one that sets the global interrupts on or off.  I go through and reset the Timer1 to 0 then set the clock source and prescalar, set up the value to compare to and then set up TIMSK1 and then enable all the interrupts.  What will happen is TCNT1 will keep counting up until it hits OCR1 and then restart back to 0.

When TCNT1 does hit OCR1 then an ISR (interrupt service routine) is generated and at I go in a write something to serial monitor.  I am still trying to wrap my head around the internals of an ISR but for now, I know that when TCNT1 = OCR1 an ISR is generated and I have to do something so that the interrupt is cleared otherwise I will have to clear it some other way.

In the meantime in loop function I printout the raw binary values associated with TCNT1 and as soon as the ISR hits it toggles a variable that causes the loop function to enter a special if clause which pauses the loop for 2000 seconds and prints a special message.  Printing in binary for TCNT1 is extremely useful because then I can use it to compare with OCR1. And thats it! This whole thing took quite a while for all those different parts to come together. The code can also be found on my github! I have found a document that does a pretty good job of describing timers which can be found on my here.

There is a lot of useful information out there and here are some useful links that I found:

http://www.robotshop.com/letsmakerobots/arduino-101-timers-and-interrupts

http://web.engr.oregonstate.edu/~traylor/ece473/lectures/tcnt1-3.pdf

http://www.gammon.com.au/interrupts

http://www.avrfreaks.net/forum/tut-c-bit-manipulation-aka-programming-101?name=PNphpBB2&file=viewtopic&t=37871

http://forum.arduino.cc/index.php?topic=134611.0

http://www.avrfreaks.net/forum/tut-newbies-guide-avr-interrupts?name=PNphpBB2&file=viewtopic&t=89843

https://oscarliang.com/arduino-timer-and-interrupt-tutorial/

https://forum.arduino.cc/index.php?topic=382681.0http://ee-classes.usc.edu/ee459/library/documents/avr_intr_vectors/

https://stackoverflow.com/questions/10854466/how-convert-two-bytes-into-one-16-bit-number

http://web.csulb.edu/~hill/ee346/Lectures/12%20Timer%20Interrupts.pdf

https://exploreembedded.com/wiki/AVR_Timer_programming

http://www.atmel.com/Images/Atmel-2505-Setup-and-Use-of-AVR-Timers_ApplicationNote_AVR130.pdf

http://class.ece.iastate.edu/cpre288/lectures/lect26_1pp.pdf

https://arduino.stackexchange.com/questions/12382/where-is-documentation-on-arduinos-internal-interrupts

https://arduinodiy.wordpress.com/author/yersinia/page/8/

http://www.avrfreaks.net/forum/tut-c-bit-manipulation-aka-programming-101?name=PNphpBB2&file=viewtopic&t=37871

http://forum.arduino.cc/index.php?topic=134611.0

http://www.avrfreaks.net/forum/tut-newbies-guide-avr-interrupts?name=PNphpBB2&file=viewtopic&t=89843

http://www.embedded.com/design/programming-languages-and-tools/4418929/An-introduction-to-function-pointers–Part-1

http://denniskubes.com/2013/03/22/basics-of-function-pointers-in-c/

 

Blinking LED by directly accessing the registers with Arduino IDE on Sparkfun ProMicro

I want to keep the train moving but after speaking to a coworker of mine I realized, that trying to make sense of the tail chain could be a tall order. Instead I should start small and build up from there. He then pointed out if I am trying to learn C and understand embedded systems, I can try toggling the register directly. How you may ask? Well it turns out Arduino IDE is basically a wrapper for C++ and I can make C/C++ commands and the compiler should be able to handle it.  After some digging around I realized that was in fact true, especially since the ino file gets a cpp added at the end then compiled.

So my project for this round was to to replace the LED calls via the IDE and directly access the registers and write to them. This took a lot of digging around and I will explain as much as I can.  Remember for now I am using the software that arduino provides to do all the compiling and uploading to the micro controller.

So digging around the most important piece of information I found was in the ATMega32U4 data sheet or you can also find the information here. It can also be found on page 66 of the data sheet. The table is very useful from the data sheet:Screenshot from 2017-07-06 00:06:18

As you can see we need to set DDxn needs to be set to 1 and the PORTxn needs to be set to 0 or 1 to make it low or high.  Why is the low and high important because that will basically make the LEDs go on or off. Now this sounds great but where do we go from here? The first thing we have to do is figure out which pins are the LEDs located on and the answer is in this picture (the image can also be found here):

Screenshot from 2017-07-06 00:13:16As you can see with this image that the yellow and green LEDs are are on PD5 and PB0. So we need to change Pin D5 and Pin B0. The way it works is we basically have to modify DDRD and DDRB (for setting input or output) and PORTB and PORTD(for setting it low or high). So the interesting part is how do we access those ports? Well the addresses to access these registers are found in the data sheet on p. 411 and the page looks like this:

Screenshot from 2017-07-06 00:19:52

So in order we to change Pin D5 we have to change the 5th bit on DDRD which is DDD5 and change the 5th bit on PORTD.  We do the same thing for Pin B and change 0th bit on DDRB and PORTB.  What do we change it you may ask? Well just change that bit to a 1 and it should enable the port. As you can see in the table we can create many different settings for the Pins. The thing that stumped me was that there were 2 address, and me being new to this whole thing got very confused. I tried using 0x0A for DDRD and 0x0B for PORTD but nothing happened.  So obviously I started digging around and my first clue came from this website (just as a side note I know they use the line:

(*(volatile unsigned char *)0x25) = 7; // Write 7 to PORTB

and I no idea what it was but after looking at this this explanation it all made sense. So 0x25 is an address and the way we go to a location in memory is via a pointer and what is happening is we take a value 0x25 and convert that to a pointer, location in memory, by doing casting it to unsigned char *. We then dereference pointer and assign a value of 7 to the register located at 0x25.  The volatile keyword simply means that the value stored in 0x25 might change at any time outside of the programs control). It seemed that he was using some other address more specifically the address in parenthesis was being used.  I went into the pins_arduino.h file that is provided with sparkfun and saw a mention of iom32u4.h file that were calling DDRB gave the following result: #define DDRB _SFR_IO8(0x04).  Now they are using the address provided outside of the parenthesis in the previous image. So I wanted to know what _SFR_IO8 was doing and I should be able to track down _SFR_IO8 to just be adding 0x20 to the address.  And hence I began I grep crawl which looked like this: grep –include ‘*.h’rnw -e “define _SFR_IO8” and in the sfr_defs.h file I found:  #define _SFR_IO8(io_addr) ((io_addr) + __SFR_OFFSET).  Here you can already see that the macro takes io_addr and adds the offset and _SFR_OFFSET value is (drum roll please) 0x20. Now I don’t know why that offset is there but I can track it down to a header file.

 

The ending code looked like this:



/* Pro Micro Test Code
 by: Nathan Seidle
 modified by: Jim Lindblom
 SparkFun Electronics
 date: September 16, 2013
 license: Public Domain - please use this code however you'd like.
 It's provided as a learning tool.

This code is provided to show how to control the SparkFun
 ProMicro's TX and RX LEDs within a sketch. It also serves
 to explain the difference between Serial.print() and
 Serial1.print().
*/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>

//int RXLED = 17; // The RX LED has a defined Arduino pin
// The TX LED was not so lucky, we'll need to use pre-defined
// macros (TXLED1, TXLED0) to control that.
// (We could use the same macros for the RX LED too -- RXLED1,
// and RXLED0.)

void setup()
{
 //pinMode(RXLED, OUTPUT); // Set RX LED as an output
 //setting up PBO
 (*(volatile unsigned char *)(0x24)) = 0x1; //setting the 0th bit in DDRB to 1 so that it can set up for output
 (*(volatile unsigned char *)(0x25)) = 0x0; //setting the 0th bit in PortB to 0 so that it can set output low

//setting up PD5
 (*(volatile unsigned char *)(0x2A)) = 0x20; //setting the 5th bit in DDRB to 1 so that it can set up for output
 (*(volatile unsigned char *)(0x2B)) = 0x0; //setting the 5th bit in PortB to so that it can set output low

// TX LED is set as an output behind the scenes

Serial.begin(9600); //This pipes to the serial monitor
 Serial1.begin(9600); //This is the UART, pipes to sensors attached to board
}

void loop()
{
 //Serial.println("Hello world"); // Print "Hello World" to the Serial Monitor
 Serial1.println("Hello!"); // Print "Hello!" over hardware UART


 //digitalWrite(RXLED, LOW); // set the LED on
 (*(volatile unsigned char *)(0x25)) = 0x0;
 //Serial.println((*(volatile unsigned char *)(0x23)));
 
 (*(volatile unsigned char *)(0x2B)) = 0x20; //setting the 5th bit in PortB to so that it can set output high
 //TXLED0; //TX LED is not tied to a normally controlled pin

delay(1000); // wait for a second
//
 //digitalWrite(RXLED, HIGH); // set the LED off
 (*(volatile unsigned char *)(0x2B)) = 0x0; //setting the 5th bit in PortB to so that it can set output low
 
 //TXLED1;
 (*(volatile unsigned char *)(0x25)) = 0x1;
 //Serial.println((*(volatile unsigned char *)(0x23)));


 delay(1000); // wait for a second
}

This file is also posted on my github and here are my list of useful links:

  1. http://www.electronicdesign.com/communications/what-s-difference-between-bit-rate-and-baud-rate
  2. http://playground.arduino.cc/FreeBSD/CLI
  3. http://www.atmel.com/webdoc/avrlibcreferencemanual/using_tools_1using_avr_as_mach_opts.html
  4. https://balau82.wordpress.com/2011/03/29/programming-arduino-uno-in-pure-c/
  5. https://arduino.stackexchange.com/questions/11762/reading-writing-to-arduino-gpio-pins-from-raw-c-code
  6. http://urbanhonking.com/ideasfordozens/2009/05/18/an_tour_of_the_arduino_interna/
  7. http://hackaday.com/2015/07/28/embed-with-elliot-there-is-no-arduino-language/
  8. https://spirle.wordpress.com/2013/02/24/programming-arduino-without-the-arduino-ide/
  9. http://www.atmel.com/webdoc/avrlibcreferencemanual/group__avr__sfr__notes.html
  10. https://paritycheck.wordpress.com/2009/03/27/what-does-this-mean-volatile-unsigned-char-0x22
  11. /http://maxembedded.com/2011/06/port-operations-in-avr/

Next time I will try to write the delay function by directly accessing the register and then will come the behemoth task of moving everything to work without Arduino IDE.

As always please let me know if you guys have any questions or find mistakes in my code.

Setting up avrdude and arduino

The end goal is to learn how to program in C using arduinos, but before that I want to start from a simpler base and build everything up instead of jumping into everything at once.  I always like to build up layers of complexity (the goal is always divide a large problem into a set of smaller problems). This is done on Ubuntu 14.04. So start with the initial things:

  1. See if the board works using preexisting arduino software
  2. Get avrdude to work

I am using ProMicro 3.3V. This is a very simple board and doesn’t have a lot of extra things going on. I am sure there are better boards for learning but this is what I had lying around. The board looks like this:

Pro Micro - 3.3V/8MHz

The first part using the blinking LEDs example I will toggle the leds near pins 16 and 8. I want to first make sure that I can even communicate device using pre-existing software. My learning technique is to build on complexity instead of all at once. I first downloaded the arduino software. After I download the software I then go to File>Preferences and then copy this link into Additional Boards Manager URLs: https://raw.githubusercontent.com/sparkfun/Arduino_Boards/master/IDE_Board_Manager/package_sparkfun_index.json. The point of this is to let the software know about the other boards that the software can connect to, otherwise it has the bare minimum of boards to use. Go to Tools>Boards>Board Manager and then look for ‘sparkfun’ and install SparkFun AVR Boards or follow directions listed here. This will allow me to upload code onto the promicro. Close the software and find the .arduino* folder and then look for the file preferences.txt and in there change “upload.verbose=false” to “upload.verbose=true” so that it can help us with avrdude.

I copied the blinking code from here. The code looks like this:

/* Pro Micro Test Code
   by: Nathan Seidle
   modified by: Jim Lindblom
   SparkFun Electronics
   date: September 16, 2013
   license: Public Domain - please use this code however you'd like.
   It's provided as a learning tool.

   This code is provided to show how to control the SparkFun
   ProMicro's TX and RX LEDs within a sketch. It also serves
   to explain the difference between Serial.print() and
   Serial1.print().
*/

int RXLED = 17;  // The RX LED has a defined Arduino pin
// The TX LED was not so lucky, we'll need to use pre-defined
// macros (TXLED1, TXLED0) to control that.
// (We could use the same macros for the RX LED too -- RXLED1,
//  and RXLED0.)

void setup()
{
 pinMode(RXLED, OUTPUT);  // Set RX LED as an output
 // TX LED is set as an output behind the scenes

 Serial.begin(9600); //This pipes to the serial monitor
 Serial1.begin(9600); //This is the UART, pipes to sensors attached to board
}

void loop()
{
 Serial.println("Hello world");  // Print "Hello World" to the Serial Monitor
 Serial1.println("Hello!");  // Print "Hello!" over hardware UART

 digitalWrite(RXLED, LOW);   // set the LED on
 TXLED0; //TX LED is not tied to a normally controlled pin
 delay(1000);              // wait for a second
 digitalWrite(RXLED, HIGH);    // set the LED off
 TXLED1;
 delay(1000);              // wait for a second
}

Once the code is copied over to the Arduino IDE then save the program and then Sketch>Verify/Compile.  To export the binary hex file which we will use in setting up avrdude go to Sketch>Export compiled Binary.  Once these are both done it is time to upload everything to the promicro which is done by doing Sketch>Upload and the resulting verbose output should look something like this:

Sketch uses 5078 bytes (17%) of program storage space. Maximum is 28672 bytes.
Global variables use 346 bytes (13%) of dynamic memory, leaving 2214 bytes for local variables. Maximum is 2560 bytes.
Forcing reset using 1200bps open/close on port /dev/ttyACM0
PORTS {/dev/ttyACM0, } / {} => {}
PORTS {} / {/dev/ttyACM0, } => {/dev/ttyACM0, }
Found upload port: /dev/ttyACM0
/home/ashwini/Downloads/arduino-1.8.3/hardware/tools/avr/bin/avrdude -C/home/ashwini/.arduino15/packages/SparkFun/hardware/avr/1.1.6/avrdude.conf -v -patmega32u4 -cavr109 -P/dev/ttyACM0 -b57600 -D -Uflash:w:/tmp/arduino_build_264931/blinky.ino.hex:i

avrdude: Version 6.3, compiled on Jan 17 2017 at 11:00:16
Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
Copyright (c) 2007-2014 Joerg Wunsch

System wide configuration file is “/home/ashwini/.arduino15/packages/SparkFun/hardware/avr/1.1.6/avrdude.conf”
User configuration file is “/home/ashwini/.avrduderc”
User configuration file does not exist or is not a regular file, skipping

Using Port : /dev/ttyACM0
Using Programmer : avr109
Overriding Baud Rate : 57600
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 “/tmp/arduino_build_264931/blinky.ino.hex”
avrdude: writing flash (5078 bytes):

Writing | ################################################## | 100% 0.40s

avrdude: 5078 bytes of flash written
avrdude: verifying flash memory against /tmp/arduino_build_264931/blinky.ino.hex:
avrdude: load data flash data from input file /tmp/arduino_build_264931/blinky.ino.hex:
avrdude: input file /tmp/arduino_build_264931/blinky.ino.hex contains 5078 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 0.06s

avrdude: verifying …
avrdude: 5078 bytes of flash verified

avrdude done. Thank you.

You should 2 LEDs flashing in an alternating fashion.  If you don’t get his output then it means  you have done this right.  Also if you don’t get the long output it means that you have probably not set upload.verbose to true.

Loading the Hex directly from avrdude

The arduino software verbose output was pretty useful it gave us a pretty good understanding of what is happening under the hood for the upload process.

I used the output to figure out how to run avrdude from command line.  Take a look at the following output:

/home/ashwini/Downloads/arduino-1.8.3/hardware/tools/avr/bin/avrdude -C/home/ashwini/.arduino15/packages/SparkFun/hardware/avr/1.1.6/avrdude.conf -v -patmega32u4 -cavr109 -P/dev/ttyACM0 -b57600 -D -Uflash:w:/tmp/arduino_build_264931/blinky.ino.hex:i

I replaced “/home/ashwini/Downloads/arduino-1.8.3/hardware/tools/avr/bin/avrdude” with the my machine’s version of avrdude (I had to upgrade to avrdude 6.3 on Ubuntu 14.04, which is outlined here).

Then next part was to get my own version of avrdude.conf file.  This file is used to figure out how avrdude is going to talk to a certain chip type.  If you go in the file and look for “ATMega32U4” you should start seeing information about the chip and what kind of memory is available.  I copied mine from the sparkfun github repo then extracted the bz2 file and copied over the avrdude.conf file to my git repo.

The -p indicates the part number which is found in the avrdude.conf file, -c is the programmer file which is also in the conf file, -P is the port, -D is disable autoerase for flash memory, -U performs a memory operation, flash is the memory type to do the operation on and w indicates that we will read data from a specified file which is the hex file and write it to device memory, and the i indicates the type of hex file it which in our case is an Intel Hex.  This information can also be found when you type in “man avrdude”.

The other thing to note was that for Promicro you have to open the device at a baud rate of 1200 to reset the device and only after that can you load all the hex file. This is done by the following set of lines:

stty -F /dev/serial/by-id/usb-SparkFun_SparkFun_Pro_Micro-if00 1200;
sleep 1s;

and then you can do:

avrdude -C/home/ashwini/git-repos/arduino/avr-1.1.6/avrdude.conf -v -patmega32u4 -cavr109 -P/dev/ttyACM0 -b57600 -D -Uflash:w:/home/ashwini/git-repos/arduino/blinky/blinky.ino.promicro.hex:i -v

This is also in a shell file called: blinky_avr_script.sh . You can see i went through multiple iterations to slowly remove parts of the arduino stuff until I got to a point where I can run it seperately.

Once all this was completed my output looked something like this:

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

System wide configuration file is “/home/ashwini/git-repos/arduino/avr-1.1.6/avrdude.conf”
User configuration file is “/home/ashwini/.avrduderc”
User configuration file does not exist or is not a regular file, skipping

Using Port : /dev/ttyACM0
Using Programmer : avr109
Overriding Baud Rate : 57600
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: safemode: hfuse reads as D8
avrdude: safemode: efuse reads as FB
avrdude: reading input file “/home/ashwini/git-repos/arduino/blinky/blinky.ino.promicro.hex”
avrdude: writing flash (5078 bytes):

Writing | ################################################## | 100% 0.41s

avrdude: 5078 bytes of flash written
avrdude: verifying flash memory against /home/ashwini/git-repos/arduino/blinky/blinky.ino.promicro.hex:
avrdude: load data flash data from input file /home/ashwini/git-repos/arduino/blinky/blinky.ino.promicro.hex:
avrdude: input file /home/ashwini/git-repos/arduino/blinky/blinky.ino.promicro.hex contains 5078 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 0.06s

avrdude: verifying …
avrdude: 5078 bytes of flash verified

avrdude: safemode: hfuse reads as D8
avrdude: safemode: efuse reads as FB
avrdude: safemode: Fuses OK (E:FB, H:D8, L:DE)

avrdude done. Thank you.

Just as a side note the ProMicro is similar to arduino leonardo. I hope this helps! Let me know if you have any questions or suggestions on how to improve the information.

Side note: I ran into issues accessing the /dev/ttyACM0 and blacklisted the device from the modem manager as described here. I went into /etc/udev/rules.d/77-mm-usb-device-blacklist.rules and added:

ATTRS{idVendor}==”1b4f”, ATTRS{idProduct}==”9203″, ENV{ID_MM_DEVICE_IGNORE}=”1″
ATTRS{idVendor}==”1b4f”, ATTRS{idProduct}==”9204″, ENV{ID_MM_DEVICE_IGNORE}=”1″

Some people had to actually remove network-manager and/or modem-manager, and only then it would work for them. This is why it is important to get everything working before hand before you start going to the command line approach.

Here are a list of useful links:

https://balau82.wordpress.com/2011/03/29/programming-arduino-uno-in-pure-c/
https://www.sparkfun.com/products/12640https://learn.sparkfun.com/tutorials/pro-micro–fio-v3-hookup-guide
https://learn.sparkfun.com/tutorials/pro-micro–fio-v3-hookup-guide/troubleshooting-and-faq
http://forum.arduino.cc/index.php?topic=217910.0
http://forum.arduino.cc/index.php?topic=111213.0
http://cholla.mmto.org/computers/arduino/boards/promicro/
http://www.nongnu.org/avrdude/user-manual/avrdude_4.html#Option-Descriptions
http://ubuntuhandbook.org/index.php/2017/01/install-avrdude-6-4-ubuntu-16-04/
https://github.com/sparkfun/Arduino_Boards/blob/master/IDE_Board_Manager/sparkfunboards.1.1.6.tar.bz2
http://xcom.ee/project_files/beer_temp2/beertemp2_buutload_howto.txt
https://www.arduino.cc/en/Guide/ArduinoLeonardoMicrot

All the documentation and the relevant code can be found on my github