Finding address of MS5607 by bit banging I2C with arduino uno in C and Sketch

This has been one my bigger solo projects to get an understanding of how bit banging works and I didn’t want to use the pre-built I2C (I squared C) module because I wanted to learn how I2C communication works. I quickly realized how difficult this actually was. In order to get a good understanding I had to first learn how I2C protocol works. I used boldinventions website to understand how the I2C protocol works. They have a great graphic of what is going on:

 

You can see that there are 2 connection one is SCL (clock) and the other is SDA (data). So the clock sets when the system reads. When the clock is high the SDA line is read. There is a master and a slave and clock is driven by the master and they both send data back and forth on the SDA line. In order to communicate with the slave we have to address the slave. So in the picture above you can see that in order to initiate the conversation we send a start signal. The start signal is sent by setting SDA to low when SCL is high. The next step is to send the address of the device and in this case they send 1011001 (0x59) where the 1s are high and 0s are low. The next bit that is sent is to either to write to that address or read from the address. The next is for the master to wait for an acknowledge to make sure the slave got the message and it responds with an ack bit where the ack bit goes low(this took me a while to get). If the ack bit stays high then it means that the message was no received(think of ack bit sending either 1 or 0, if 1 is received then the slave did not acknowledge but if 0 is received then the slave received the message). The part that is missing is sending the stop bit when the SCL is high and SDA goes from low to high. In order to get started I first started with writing my code in sketch:

int sda = 6;
int scl = 7;
void setup() {
 // put your setup code here, to run once:
 pinMode(sda,OUTPUT);
 digitalWrite(sda,HIGH);
 pinMode(scl,OUTPUT);
 digitalWrite(scl,HIGH);
 delay(3000);
 Serial.begin(9600);
 sendStop();
 sendStart();
 int counter = 0;
 int ack=1;
 String addrstr = "11101100";
 String addrstr1 = "11000010";
 String addrstr2 = "00000010";
 sendStr(addrstr1);
 Serial.println('D',HEX);
 ack = getAck();
 checkAck(counter,ack);
 /*sendStop();
 sendStart();
 ack=1;
 sendStr(addrstr2);
 Serial.println('D');
 ack = getAck();
 checkAck(counter,ack);*/
 sendStop();
 sendStart();
 ack=1;
 sendStr(addrstr);
 ack = getAck();
 checkAck(counter,ack);
 sendStop();
 Serial.println('E',HEX);
 Serial.println('E',HEX);
 Serial.println('E',HEX);
 Serial.println('E',HEX);
}

void sendReset(){
 String res = "00011110";
 int counter;
 Serial.print("Reset Data :");
 for(counter=0;counter<8;counter++){
 sendData(res[counter]-'0');
 }
 Serial.println();
}

void checkAck(int counter,int ack){
 if(ack == LOW){
 Serial.println('S',HEX);
 } 
 else{
 Serial.println('F',HEX);
 }
}

void sendStr(String addrstr){
 int counter = 0;
 for(counter=0;counter<8;counter++){
 sendData(addrstr[counter]-'0');
 }
}

void loop() {
 // put your main code here, to run repeatedly:
}

void sendZeros(int diff){
 int i = 0;
 for(i=0;i<diff;i++){
 sendData((unsigned int)('0'-'0'));
 //Serial.println("in for loop");
 }
}

unsigned int getAck(){
 Serial.println('a',HEX);
 unsigned int ack=1;
 delay(10);
 Serial.println(PIND,HEX);
 pinMode(sda,INPUT);
 delay(10);
 Serial.println(DDRD,HEX);
 Serial.println(PORTD,HEX);
 digitalWrite(scl,HEX);
 delay(10);
 Serial.println(PIND,HEX);
 ack = digitalRead(sda);
 delay(10);
 Serial.println(PIND,HEX);
 digitalWrite(scl,HIGH);
 delay(10);
 Serial.println(PIND,HEX);
 digitalWrite(scl,LOW);
 delay(10);
 Serial.println(PIND,HEX);
 pinMode(sda,OUTPUT);
 Serial.println(DDRD,HEX);
 Serial.println(PORTD,HEX);
 Serial.println('a',HEX);
 return ack;
}

void sendData(unsigned int data){
 Serial.println('d',HEX);
 Serial.println(data,HEX);
 //Serial.print(data,HEX);
 if(data==0){
 digitalWrite(sda,LOW);}
 else{
 digitalWrite(sda,HIGH);}
 delay(10);
 Serial.println(PIND,HEX);
 digitalWrite(scl,HIGH);
 delay(10);
 Serial.println(PIND,HEX);
 digitalWrite(scl,LOW);
 delay(10);
 Serial.println(PIND,HEX);
 Serial.println('d',HEX);
}

void sendStop(){
 Serial.println('u',HEX);
 Serial.println(PIND,HEX);
 digitalWrite(scl,LOW);
 delay(10);
 Serial.println(PIND,HEX);
 digitalWrite(sda,LOW);
 delay(10);
 Serial.println(PIND,HEX);
 digitalWrite(sda,HIGH);
 delay(10);
 Serial.println(PIND,HEX);
 digitalWrite(scl,HIGH);
 delay(10);
 Serial.println(PIND,HEX);
 Serial.println('u',HEX);
}

void sendStart(){
 Serial.println('t',HEX);
 Serial.println(PIND,HEX);
 digitalWrite(scl,HIGH);
 delay(10);
 Serial.println(PIND,HEX);
 digitalWrite(sda,LOW);
 delay(10);
 Serial.println(PIND,HEX);
 digitalWrite(scl,LOW);
 delay(10);
 Serial.println(PIND,HEX);
 Serial.println('t',HEX);
}

The first thing I did was find the address of the PARALLAX MS5607 which I found in the manual to be 111011Cx where Cx is the complementary value of the CSB pin which in my case was 0. I converted that to a binary string

String addrstr = "11101100";

I used the serial port a lot on this one because I needed to know what was being outputted. I created a sendStop function which

void sendStop(){
 Serial.println('u',HEX);
 Serial.println(PIND,HEX);
 digitalWrite(scl,LOW);
 delay(10);
 Serial.println(PIND,HEX);
 digitalWrite(sda,LOW);
 delay(10);
 Serial.println(PIND,HEX);
 digitalWrite(sda,HIGH);
 delay(10);
 Serial.println(PIND,HEX);
 digitalWrite(scl,HIGH);
 delay(10);
 Serial.println(PIND,HEX);
 Serial.println('u',HEX);
}
As you can see I have a lot of Serial.println because I needed to print out the exact pin states in order to see that things were being toggled properly. I then send it through the start function
void sendStart(){
 Serial.println('t',HEX);
 Serial.println(PIND,HEX);
 digitalWrite(scl,HIGH);
 delay(10);
 Serial.println(PIND,HEX);
 digitalWrite(sda,LOW);
 delay(10);
 Serial.println(PIND,HEX);
 digitalWrite(scl,LOW);
 delay(10);
 Serial.println(PIND,HEX);
 Serial.println('t',HEX);
}
this allowed me to send a start signal only using the GPIO pins. Just FYI I am using pins 6 and 7 as outline above. As always I have lots of print statements because I kept running into all sorts of issues. I made a function for writing data where the bit is put is when the SCL clock goes high and had function that checked if the acknowledge worked.
unsigned int getAck(){
 Serial.println('a',HEX);
 unsigned int ack=1;
 delay(10);
 Serial.println(PIND,HEX);
 pinMode(sda,INPUT);
 delay(10);
 Serial.println(DDRD,HEX);
 Serial.println(PORTD,HEX);
 digitalWrite(scl,HEX);
 delay(10);
 Serial.println(PIND,HEX);
 ack = digitalRead(sda);
 delay(10);
 Serial.println(PIND,HEX);
 digitalWrite(scl,HIGH);
 delay(10);
 Serial.println(PIND,HEX);
 digitalWrite(scl,LOW);
 delay(10);
 Serial.println(PIND,HEX);
 pinMode(sda,OUTPUT);
 Serial.println(DDRD,HEX);
 Serial.println(PORTD,HEX);
 Serial.println('a',HEX);
 return ack;
}

void sendData(unsigned int data){
 Serial.println('d',HEX);
 Serial.println(data,HEX);
 //Serial.print(data,HEX);
 if(data==0){
 digitalWrite(sda,LOW);}
 else{
 digitalWrite(sda,HIGH);}
 delay(10);
 Serial.println(PIND,HEX);
 digitalWrite(scl,HIGH);
 delay(10);
 Serial.println(PIND,HEX);
 digitalWrite(scl,LOW);
 delay(10);
 Serial.println(PIND,HEX);
 Serial.println('d',HEX);
}
What was interesting for me was to set ack==0 instead of 1 and the key part is that the slave pull SDA down which causes the SDA pin to go low. I had to output after each step because I didn’t know when things were failing and sometimes I had to output PORTD and DDRD just to make sure pins are being configured right. I sent through 2 address, where one was wrong and one is right to make sure that the wrong one doesn’t impact anything. I wanted to do this because when you are bit banging a wrong address shouldn’t do anything.
 String addrstr = "11101100";
 String addrstr1 = "11000010";
I then looked at the console output and it should be clear that when ack is 0 (slave received the message) I should get the ‘S’ character in hex otherwise I would just get ‘F’. I will show the output in a bit, but for now know that it worked. Once this was done I wanted to convert everything to C, because I wanted to :). The one thing to note is I placed a bunch of ‘E’ characters at the end of the program to let me know that when I see 4 repeating character I know that the code went through. The first try at my C program was just to mimc the ino file that I created.
filename: bit_bang_MS5607_working.c
#include<stdlib.h>
#include<stdio.h>
#include<avr/interrupt.h>
#include<avr/io.h> 
#include<util/delay.h>

#define FOSC 16000000 
#define BAUD 9600
#define MYUBRR FOSC/16/BAUD-1 
//#define MYUBRR 103
#define SCL PORTD7
#define SDA PORTD6

void USART_init(unsigned int ubrr);
void USART_transmit(char data);
unsigned char USART_recieve(void);
unsigned int getAck();
void sendStart();
void sendStop();
void checkAck(unsigned int ack);
void sendData(unsigned char data);
void sendStr(char data[8]);
void morepininfo();

int main(){
 //char data={"0000000"};//"Hello!";
 /* String addrstr = "11101100";
 String addrstr1 = "11000010";
 String addrstr2 = "00000010";
 */




char* addrstr = "11101100";
 char* addrstr1 = "11000010";
 char* addrstr2 = "10101010";
 unsigned int ack;
 USART_init(MYUBRR);
 _delay_ms(10000);
 DDRD = 0;
 PORTD = 0;
 //DDRD = (0<<DDD6)|(1<<DDD7)|(1<<DDD4);
 DDRD = (1<<DDD6)|(1<<DDD7)|(1<<DDD4);
 //PORTD = (0<<SDA)|(1<<SCL)|(1<<PORTD4);
 PORTD = (1<<SDA)|(1<<SCL)|(1<<PORTD4);
 //first address
 sendStop();
 sendStart();
 sendStr(addrstr1);
 USART_transmit('D');
 ack = getAck();
 checkAck(ack);
 sendStop();
 //second address
 DDRD = 0;
 PORTD = 0;
 //DDRD = (0<<DDD6)|(1<<DDD7)|(1<<DDD4);
 DDRD = (1<<DDD6)|(1<<DDD7)|(1<<DDD4);
 //PORTD = (0<<SDA)|(1<<SCL)|(1<<PORTD4);
 PORTD = (1<<SDA)|(1<<SCL)|(1<<PORTD4);
 //morepininfo();
 sendStop();
 sendStart();
 sendStr(addrstr);
 USART_transmit('D');
 ack=getAck();
 checkAck(ack);
 sendStop();
 USART_transmit('E'); 
 USART_transmit('E');
 USART_transmit('E');
 USART_transmit('E');

while(1){
 _delay_ms(10);
 PORTD |= (1<<PORTD4);
 _delay_ms(10);
 PORTD ^= (1<<PORTD4);
 _delay_ms(10);
 USART_transmit(PIND+65);
 _delay_ms(5000);
 if ((PIND)&(1<<SDA)){
 USART_transmit('i');
 _delay_ms(10);
 PORTD ^= (1<<SCL);
 }
 //USART_transmit(97);
 //data = USART_recieve();
 //USART_transmit(data);
 //_delay_ms(1000);
}
}

void morepininfo(){
 USART_transmit('p');
 USART_transmit(PORTD);
 USART_transmit(DDRD);
 USART_transmit('p');
}

void checkAck(unsigned int ack){
 if(ack == 0){
 USART_transmit('S');
 }
 else{
 USART_transmit('F');
 }
}

void sendStr(char addr[8]){
 int i = 0;
 for(i=0;i<8;i++){
 sendData(addr[i]);
 }
}

void sendStart(){
 USART_transmit('t');
 USART_transmit(PIND);
 PORTD |= (1<<SCL); //setting scl low
 _delay_ms(10);
 USART_transmit(PIND);
 PORTD = (0<<SDA)|(1<<SCL);
 _delay_ms(10);
 USART_transmit(PIND);
 PORTD = (0<<SDA)|(0<<SCL);
 _delay_ms(10);
 USART_transmit(PIND);
 USART_transmit('t');
}

void sendStop(){
 USART_transmit('u');
 USART_transmit(PIND);
 PORTD = (0<<SCL)|(1<<SDA);
 _delay_ms(10);
 USART_transmit(PIND);
 PORTD = (0<<SDA)|(0<<SCL);
 _delay_ms(10);
 USART_transmit(PIND);
 PORTD = (1<<SDA)|(0<<SCL);
 _delay_ms(10);
 USART_transmit(PIND);
 PORTD = (1<<SDA)|(1<<SCL);
 _delay_ms(10);
 USART_transmit(PIND);
 USART_transmit('u');
}




void sendData(unsigned char data){
 USART_transmit('d');
 int val = data-'0';
 USART_transmit(val);
 USART_transmit(PIND);
 PORTD = (val<<SDA)|(0<<SCL);
 _delay_ms(10);
 USART_transmit(PIND);
 PORTD = (val<<SDA)|(1<<SCL);
 _delay_ms(10);
 USART_transmit(PIND);
 PORTD = (val<<SDA)|(0<<SCL);
 _delay_ms(10);
 USART_transmit(PIND);
 USART_transmit('d');
}

unsigned int getAck(){
 USART_transmit('a');
 unsigned int ack=1;
 _delay_ms(10);
 USART_transmit(PIND);
 //convert PIND6 to input
 DDRD = (0<<DDD6)|(1<<DDD7)|(1<<DDD4);
 //PORTD = (1<<SDA)|(1<<SCL)|(1<<PORTD4); 
 PORTD = (1<<SDA)|(1<<SCL);
 USART_transmit(DDRD);
 USART_transmit(PORTD);
 _delay_ms(10);
 PORTD |= (1<<SCL);
 //_delay_ms(10000);
 USART_transmit(PIND);
 _delay_ms(10);
 USART_transmit(PIND);
 if(~(PIND)&(1<<SDA)){
 ack = 0;}
 _delay_ms(10);
 USART_transmit(PIND);
 PORTD |= (1<<SCL);
 _delay_ms(10);
 USART_transmit(PIND);
 PORTD = (0<<SCL);
 _delay_ms(10);
 USART_transmit(PIND);
 //set pin6 to output
 DDRD = (1<<DDD6)|(1<<DDD7)|(1<<DDD4);
 PORTD = (1<<SDA)|(1<<SCL)|(1<<PORTD4);
 _delay_ms(10);
 USART_transmit(DDRD);
 USART_transmit(PORTD);
 USART_transmit('a');
 return ack;
}




void USART_init(unsigned int ubrr){
 UCSR0B = (1<<TXEN0)|(1<<RXEN0);

//choose asynchronous mode
 UCSR0C = 0;
 UCSR0C = (0<<UMSEL01)|(0<<UMSEL00);
 UCSR0C |= (1<<UCSZ01)|(1<<UCSZ00);
 UCSR0C |= (1<<USBS0);
 /*//setting UBRR TO 103 for 9600 baudrate
 UBRR0H = 0;
 UBRR0L = 0b01100111; */
 UBRR0H = (unsigned char)(ubrr>>8);
 UBRR0L = (unsigned char)ubrr;
}

void USART_transmit(char data){
 char temp='a';//initialize to a certain character
 //while(temp){
 //temp = *(data++);//go through each character one by one until all the data has been put out
 while( !(UCSR0A & (1<<UDRE0)) ) //
 ;
 //UDR0 = temp;
 UDR0 = data;
 //}
 _delay_ms(10);
}

unsigned char USART_recieve(void){
 /*wait for data to be recieved, this is important because the data register has to get filled up and a flag gets created when a stop bit is set high*/
 while(!(UCSR0A & (1<<RXC0) ))
 ;
 //once the stop bit is set high then read directly from UDRN
 return UDR0;
}
The UART material is the same as my previous post. So I am not going to repeat that but I used the code in order to debug my software. It is very similar to sketch file except I am directly calling the ports. I am using USART_transmit instead of Serial.println and I am setting a pin to be input by using
DDRD = (0<<DDD6)|(1<<DDD7)|(1<<DDD4);
 PORTD = (1<<SDA)|(1<<SCL);
In my case PinD7 was the clock and PinD6 is the data line. Setting DDRD where bit 6 is set to 0 causes the pin to become an input pin as outline by the ATMEGA328p manual. You can see I am outputting after every single line in order to see what the pin status looks like. I was constantly comparing my sketch output with my c output.
Here is my sketch output decoded with the proper binary conversion:
intputa.csv
0x75 u
0xC1 11000001
0x43 01000011
0x3 00000011
0x43 01000011
0xC3 11000011
0x75 u
0x74 t
0xC3 11000011
0xC3 11000011
0x81 10000001
0x3 00000011
0x74 t
0x64 d
0x1 00000001
0x41 01000001
0xC3 11000011
0x43 01000011
0x64 d
0x64 d
0x1 00000001
0x43 01000011
0xC3 11000011
0x43 01000011
0x64 d
0x64 d
0x0 00000000
0x3 00000011
0x83 10000011
0x3 00000011
0x64 d
0x64 d
0x0 00000000
0x3 00000011
0x83 10000011
0x3 00000011
0x64 d
0x64 d
0x0 00000000
0x3 00000011
0x83 10000011
0x3 00000011
0x64 d
0x64 d
0x0 00000000
0x3 00000011
0x83 10000011
0x3 00000011
0x64 d
0x64 d
0x1 00000001
0x43 01000011
0xC3 11000011
0x43 01000011
0x64 d
0x64 d
0x0 00000000
0x3 00000011
0x83 10000011
0x3 00000011
0x64 d
0x44 D
0x61 a
0x3 00000011
0x80 10000000
0x0 00000000
0xC3 11000011
0xC3 11000011
0xC3 11000011
0x43 01000011
0xC0 11000000
0x0 00000000
0x46 F
0x75 u
0x1 00000001
0x1 00000001
0x1 00000001
0x43 01000011
0xC3 11000011
0x75 u
0x74 t
0xC3 11000011
0xC3 11000011
0x81 10000001
0x3 00000011
0x74 t
0x64 d
0x1 00000001
0x43 01000011
0xC3 11000011
0x43 01000011
0x64 d
0x64 d
0x1 00000001
0x43 01000011
0xC3 11000011
0x43 01000011
0x64 d
0x64 d
0x1 00000001
0x43 01000011
0xC3 11000011
0x43 01000011
0x64 d
0x64 d
0x0 00000000
0x3 00000011
0x83 10000011
0x3 00000011
0x64 d
0x64 d
0x1 00000001
0x43 01000011
0xC3 11000011
0x43 01000011
0x64 d
0x64 d
0x1 00000001
0x43 01000011
0xC3 11000011
0x43 01000011
0x64 d
0x64 d
0x0 00000000
0x3 00000011
0x83 10000011
0x3 00000011
0x64 d
0x64 d
0x0 00000000
0x3 00000011
0x83 10000011
0x3 00000011
0x64 d
0x61 a
0x1 00000001
0x80 10000000
0x0 00000000
0x83 10000011
0x83 10000011
0x83 10000011
0x43 01000011
0xC0 11000000
0x0 00000000
0x53 S
0x75 u
0x1 00000001
0x1 00000001
0x1 00000001
0x43 01000011
0xC3 11000011
0x75 u
0x45 E
0x45 E
0x45 E
0x45 E
You can see the last address was a Success with character 0x53 indicating an S character. After hours of comparing my sketch output with my C code output I was finally able to get the system to work and the output looked like this:
0x75 u
0xd3 11010011
0x43 01000011
0x03 00000011
0x43 01000011
0xc3 11000011
0x75 u
0x74 t
0xc3 11000011
0xc3 11000011
0x83 10000011
0x03 00000011
0x74 t
0x64 d
0x01 00000001
0x03 00000011
0x43 01000011
0xc3 11000011
0x43 01000011
0x64 d
0x64 d
0x01 00000001
0x43 01000011
0x43 01000011
0xc3 11000011
0x43 01000011
0x64 d
0x64 d
0x00 00000000
0x43 01000011
0x03 00000011
0x83 10000011
0x03 00000011
0x64 d
0x64 d
0x00 00000000
0x03 00000011
0x03 00000011
0x83 10000011
0x03 00000011
0x64 d
0x64 d
0x00 00000000
0x03 00000011
0x03 00000011
0x83 10000011
0x03 00000011
0x64 d
0x64 d
0x00 00000000
0x03 00000011
0x03 00000011
0x83 10000011
0x03 00000011
0x64 d
0x64 d
0x01 00000001
0x03 00000011
0x43 01000011
0xc3 11000011
0x43 01000011
0x64 d
0x64 d
0x00 00000000
0x43 01000011
0x03 00000011
0x83 10000011
0x03 00000011
0x64 d
0x44 D
0x61 a
0x03 00000011
0x90 10010000
0xc0 11000000
0xc3 11000011
0xc3 11000011
0xc3 11000011
0xc3 11000011
0x43 01000011
0xd0 11010000
0xd0 11010000
0x61 a
0x46 F
0x75 u
0xf3 11110011
0x43 01000011
0x03 00000011
0x43 01000011
0xc3 11000011
0x75 u
0x75 u
0xd3 11010011
0x43 01000011
0x03 00000011
0x43 01000011
0xc3 11000011
0x75 u
0x74 t
0xc3 11000011
0xc3 11000011
0x83 10000011
0x03 00000011
0x74 t
0x64 d
0x01 00000001
0x03 00000011
0x43 01000011
0xc3 11000011
0x43 01000011
0x64 d
0x64 d
0x01 00000001
0x43 01000011
0x43 01000011
0xc3 11000011
0x43 01000011
0x64 d
0x64 d
0x01 00000001
0x43 01000011
0x43 01000011
0xc3 11000011
0x43 01000011
0x64 d
0x64 d
0x00 00000000
0x43 01000011
0x03 00000011
0x83 10000011
0x03 00000011
0x64 d
0x64 d
0x01 00000001
0x03 00000011
0x43 01000011
0xc3 11000011
0x43 01000011
0x64 d
0x64 d
0x01 00000001
0x43 01000011
0x43 01000011
0xc3 11000011
0x43 01000011
0x64 d
0x64 d
0x00 00000000
0x43 01000011
0x03 00000011
0x83 10000011
0x03 00000011
0x64 d
0x64 d
0x00 00000000
0x03 00000011
0x03 00000011
0x83 10000011
0x03 00000011
0x64 d
0x44 D
0x61 a
0x03 00000011
0x90 10010000
0xc0 11000000
0x83 10000011
0x83 10000011
0x83 10000011
0x83 10000011
0x43 01000011
0xd0 11010000
0xd0 11010000
0x61 a
0x53 S
0x75 u
0xf3 11110011
0x63 01100011
0x03 00000011
0x43 01000011
0xc3 11000011
0x75 u
0x45 E
0x45 E
0x45 E
0x45 E
I created a simple python code to parse all my information because I couldn’t understand the entire output.
import pandas as pd
import numpy as np
import sys
fname = sys.argv[1]
infname = sys.argv[2]
analysisflag = sys.argv[3]
if analysisflag=='0':
 f = open(infname,'r')
 readout = f.readline()
 readout = readout.split('\n')[0]
 readout = readout.split(" ")
elif analysisflag=='1':
 readout = pd.read_csv(infname,delimiter='\n',header=None)[0].values.tolist()
else:
 sys.exit();
readout = np.array(['0x'+x for x in readout])
specialchars = np.array(['D','E','S','F','t','u','d','a','p','A'])
specialhex = [hex(ord(x)) for x in specialchars]
binlist = np.array([format(int(x,16),'08b') for x in readout])
for idx,hexOI in enumerate(specialhex):
 locs = np.where(readout==hexOI)[0]
 if len(locs)>0:
 binlist[locs]=specialchars[idx]
df=pd.DataFrame()
df['hexval']=readout
df['binval']=binlist
df.to_csv(fname+'.csv',header=None,index=None,sep='\t')
This allowed me to parse the output from both the sketch and minicom (remember to turn on linewrap when copying the output for minicom), with some manual massaging of the data. This is where having ‘E’ multiple times helped because then I would just look for a hex value that was repeated 4 times in a row and I knew to copy till then. Also, the reason I chose hex was because writing out the character for 0x1 results in some garbage characters. Having the outputs was a big deal because it made it so much easier for me to locate issues such as in the C code where I wasn’t correctly creating the stop bit.
Now I could prove that I could get things to work, I tried to make a loop that went through and tried to find the right address. The only difference in the code for sketch file is that there is a for loop that goes through every value until ack==0 from which it says that it has found the address.
int sda = 7;//9;
int scl = 6;//8;
void setup() {
 // put your setup code here, to run once:
 pinMode(sda,OUTPUT);
 digitalWrite(sda,HIGH);
 pinMode(scl,OUTPUT);
 digitalWrite(scl,HIGH);
 Serial.begin(9600);
 unsigned int len = 0;
 sendStop();
 int counter = 0;
 int ack=1;
 int idx = 0;
 for(counter=0;counter<128;counter++){
  sendStart();
  ack=1;
  Serial.print("Counter: ");Serial.println(counter);
  String binval = String(counter,BIN);
  String eightbitval = create8bit(binval);
  sendStr(eightbitval);
  Serial.print("Data: ");Serial.println(eightbitval);
  Serial.println();
  ack = getAck();
  if(ack == LOW){
  Serial.print("Address: ");
  Serial.println(counter,HEX);
  break;
  }
  sendStop();
  Serial.println();
  Serial.println("Done with one cycle");
 } 
 Serial.println("Exiting Setup!");
}

void loop() {
 // put your main code here, to run repeatedly:
}

String create8bit(String binval){
 int len = binval.length();
 int idx=0;int idx2=0;
 String largebinval = "0000000"+binval;
 int fullLen = largebinval.length();
 String bin8bitval = "00000000";
 for(idx=fullLen-7;idx<fullLen;idx++){
 bin8bitval[idx2] = largebinval[idx];idx2++;
 }
 return bin8bitval;
}

void sendStr(String addrstr){
 int counter = 0;
 Serial.print("Data: ");
 for(counter=0;counter<8;counter++){
 sendData(addrstr[counter]-'0');
 }
 Serial.println();
}

void sendZeros(int diff){
 int i = 0;
 for(i=0;i<diff;i++){
 sendData((unsigned int)('0'-'0'));
 //Serial.println("in for loop");
 }
}

unsigned int getAck(){
 unsigned int ack=1;
 delay(10);
 pinMode(sda,INPUT);
 delay(10);
 digitalWrite(scl,HIGH);
 delay(10);
 ack = digitalRead(sda);
 delay(10);
 digitalWrite(scl,HIGH);
 delay(10);
 digitalWrite(scl,LOW);
 delay(10);
 Serial.print("ack: ");
 Serial.println(ack);
 pinMode(sda,OUTPUT);
 return ack;
}

void sendData(unsigned int data){
 //Serial.print("Data :");
 Serial.print(data,HEX);
 if(data==0){
 digitalWrite(sda,LOW);}
 else{
 digitalWrite(sda,HIGH);}
 delay(10);
 digitalWrite(scl,HIGH);
 delay(10);
 digitalWrite(scl,LOW);
 delay(10);
}

void sendStop(){
 digitalWrite(scl,LOW);
 delay(10);
 digitalWrite(sda,LOW);
 delay(10);
 digitalWrite(sda,HIGH);
 delay(10);
 digitalWrite(scl,HIGH);
 delay(10);
}

void sendStart(){
 digitalWrite(scl,HIGH);
 delay(10);
 digitalWrite(sda,LOW);
 delay(10);
 digitalWrite(scl,LOW);
 delay(10);
}
The only things that were mainly added were:
 for(counter=0;counter<128;counter++){
 sendStart();
 ack=1;
 Serial.print("Counter: ");Serial.println(counter);
 String binval = String(counter,BIN);
 String eightbitval = create8bit(binval);
 sendStr(eightbitval);
 Serial.print("Data: ");Serial.println(eightbitval);
 Serial.println();
 ack = getAck();
 if(ack == LOW){
 Serial.print("Address: ");
 Serial.println(counter,HEX);
 break;
 }
 sendStop();
 Serial.println();
 Serial.println("Done with one cycle");
 } 
 Serial.println("Exiting Setup!");
}

void loop() {
 // put your main code here, to run repeatedly:
}

String create8bit(String binval){
 int len = binval.length();
 int idx=0;int idx2=0;
 String largebinval = "0000000"+binval;
 int fullLen = largebinval.length();
 String bin8bitval = "00000000";
 for(idx=fullLen-7;idx<fullLen;idx++){
 bin8bitval[idx2] = largebinval[idx];idx2++;
 }
 return bin8bitval;
}
All the code did was create a for loop and make sure that I am always sending an 8 bit value. It was the samething for the C code where I had to build up a function that converts a number to a binary string and sends that through.
 for(i=0;i<256;i++){
 USART_transmit(i);
 ack=1;
 sendStart();
 convert_to_binary(i,addrstr);
 //sendStr(addrstr1);
 sendStr(addrstr);
 //USART_transmit('D');
 ack = getAck();
 checkAck(ack);
 sendStop();
 if(ack==0){
 USART_transmit('A');
 USART_transmit('A');
 USART_transmit('A');
 USART_transmit(i);
 break;
 }
 //second address
 DDRD = 0;
 PORTD = 0;
 //DDRD = (0<<DDD6)|(1<<DDD7)|(1<<DDD4);
 DDRD = (1<<DDD6)|(1<<DDD7)|(1<<DDD4);
 //PORTD = (0<<SDA)|(1<<SCL)|(1<<PORTD4);
 PORTD = (1<<SDA)|(1<<SCL)|(1<<PORTD4);
 //morepininfo();
 sendStop(); 
 }
void convert_to_binary(int num, char binstr[9]){
 char temp[9] = "00000000";
 int rem=0;
 int quotient = 0;
 int idx = 7;
 while(num/2!=0){
 rem = num%2;
 num=num/2;
 //printf("quotient: %d\n",num);
 //printf("rem: %d\n",rem);
 //printf("char: %c\n",(char)rem+'0');
 temp[idx] = (char)(rem+'0');
 idx--;
 }
 
 rem = num%2;
 temp[idx] = (char)(rem+'0');
 //printf("rem: %d\n",(char)rem);
 //printf("char: %c\n",(char)(rem+'0'));
 strncpy(binstr,temp,9);
}
The converter works by dividing the number by 2 and taking the remainder until the quotient equal 0. Wikihow has a great explanation of this. This resulted in slight refactoring of the code.
bit_bang_MS5607.c
#include<stdlib.h>
#include<stdio.h>
#include<avr/interrupt.h>
#include<avr/io.h> 
#include<util/delay.h>
#include<string.h>

#define FOSC 16000000 
#define BAUD 9600
#define MYUBRR FOSC/16/BAUD-1 
//#define MYUBRR 103
#define SCL PORTD7
#define SDA PORTD6

void USART_init(unsigned int ubrr);
void USART_transmit(char data);
unsigned char USART_recieve(void);
unsigned int getAck();
void sendStart();
void sendStop();
void checkAck(unsigned int ack);
void sendData(unsigned char data);
void sendStr(char data[8]);
void morepininfo();
void convert_to_binary(int num, char binstr[9]);

int main(){

char addrstr[9] = "00000000";// = "11101100";//236
 char* addrstr1 = "11000010";//194
 char* addrstr2 = "10101010";
 unsigned int ack;
 USART_init(MYUBRR);
 _delay_ms(10000);
 DDRD = 0;
 PORTD = 0;
 //DDRD = (0<<DDD6)|(1<<DDD7)|(1<<DDD4);
 DDRD = (1<<DDD6)|(1<<DDD7)|(1<<DDD4);
 //PORTD = (0<<SDA)|(1<<SCL)|(1<<PORTD4);
 PORTD = (1<<SDA)|(1<<SCL)|(1<<PORTD4);
 //first address
 sendStop();
 int i = 0;
 for(i=0;i<256;i++){
 USART_transmit(i);
 ack=1;
 sendStart();
 convert_to_binary(i,addrstr);
 //sendStr(addrstr1);
 sendStr(addrstr);
 //USART_transmit('D');
 ack = getAck();
 checkAck(ack);
 sendStop();
 if(ack==0){
 USART_transmit('A');
 USART_transmit('A');
 USART_transmit('A');
 USART_transmit(i);
 break;
 }
 //second address
 DDRD = 0;
 PORTD = 0;
 //DDRD = (0<<DDD6)|(1<<DDD7)|(1<<DDD4);
 DDRD = (1<<DDD6)|(1<<DDD7)|(1<<DDD4);
 //PORTD = (0<<SDA)|(1<<SCL)|(1<<PORTD4);
 PORTD = (1<<SDA)|(1<<SCL)|(1<<PORTD4);
 //morepininfo();
 sendStop(); 
 }
/* sendStart();
 convert_to_binary(194,addrstr);
 sendStr(addrstr1);
 //USART_transmit('D');
 ack = getAck();
 checkAck(ack);
 sendStop();*/
 //second address
 DDRD = 0;
 PORTD = 0;
 //DDRD = (0<<DDD6)|(1<<DDD7)|(1<<DDD4);
 DDRD = (1<<DDD6)|(1<<DDD7)|(1<<DDD4);
 //PORTD = (0<<SDA)|(1<<SCL)|(1<<PORTD4);
 PORTD = (1<<SDA)|(1<<SCL)|(1<<PORTD4);
 //morepininfo();
 sendStop();
 sendStart();
 convert_to_binary(236,addrstr);
 //sendStr(addrstr);
 sendStr(addrstr);
 //USART_transmit('D');
 ack=getAck();
 checkAck(ack);
 sendStop();
 //USART_transmit('E'); 
 //USART_transmit('E');
 //USART_transmit('E');
 //USART_transmit('E');

while(1){
 _delay_ms(10);
 PORTD |= (1<<PORTD4);
 _delay_ms(10);
 PORTD ^= (1<<PORTD4);
 _delay_ms(10);
 //USART_transmit(PIND+65);
 _delay_ms(5000);
 if ((PIND)&(1<<SDA)){
 //USART_transmit('i');
 _delay_ms(10);
 PORTD ^= (1<<SCL);
 }
 ////USART_transmit(97);
 //data = USART_recieve();
 ////USART_transmit(data);
 //_delay_ms(1000);
}
}

void convert_to_binary(int num, char binstr[9]){
 char temp[9] = "00000000";
 int rem=0;
 int quotient = 0;
 int idx = 7;
 while(num/2!=0){
 rem = num%2;
 num=num/2;
 //printf("quotient: %d\n",num);
 //printf("rem: %d\n",rem);
 //printf("char: %c\n",(char)rem+'0');
 temp[idx] = (char)(rem+'0');
 idx--;
 }

 rem = num%2;
 temp[idx] = (char)(rem+'0');
 //printf("rem: %d\n",(char)rem);
 //printf("char: %c\n",(char)(rem+'0'));
 strncpy(binstr,temp,9);
}




void morepininfo(){
 //USART_transmit('p');
 //USART_transmit(PORTD);
 //USART_transmit(DDRD);
 //USART_transmit('p');
}




void checkAck(unsigned int ack){
 if(ack == 0){
 //USART_transmit('S');
 }
 else{
 //USART_transmit('F');
 }
}

void sendStr(char addr[8]){
 int i = 0;
 for(i=0;i<8;i++){
 sendData(addr[i]);
 }
}

void sendStart(){
 //USART_transmit('t');
 //USART_transmit(PIND);
 PORTD |= (1<<SCL); //setting scl low
 _delay_ms(10);
 //USART_transmit(PIND);
 PORTD = (0<<SDA)|(1<<SCL);
 _delay_ms(10);
 //USART_transmit(PIND);
 PORTD = (0<<SDA)|(0<<SCL);
 _delay_ms(10);
 //USART_transmit(PIND);
 //USART_transmit('t');
}

void sendStop(){
 //USART_transmit('u');
 //USART_transmit(PIND);
 PORTD = (0<<SCL)|(1<<SDA);
 _delay_ms(10);
 //USART_transmit(PIND);
 PORTD = (0<<SDA)|(0<<SCL);
 _delay_ms(10);
 //USART_transmit(PIND);
 PORTD = (1<<SDA)|(0<<SCL);
 _delay_ms(10);
 //USART_transmit(PIND);
 PORTD = (1<<SDA)|(1<<SCL);
 _delay_ms(10);
 //USART_transmit(PIND);
 //USART_transmit('u');
}




void sendData(unsigned char data){
 //USART_transmit('d');
 int val = data-'0';
 //USART_transmit(val);
 //USART_transmit(PIND);
 PORTD = (val<<SDA)|(0<<SCL);
 _delay_ms(10);
 //USART_transmit(PIND);
 PORTD = (val<<SDA)|(1<<SCL);
 _delay_ms(10);
 //USART_transmit(PIND);
 PORTD = (val<<SDA)|(0<<SCL);
 _delay_ms(10);
 //USART_transmit(PIND);
 //USART_transmit('d');
}

unsigned int getAck(){
 //USART_transmit('a');
 unsigned int ack=1;
 _delay_ms(10);
 //USART_transmit(PIND);
 //convert PIND6 to input
 DDRD = (0<<DDD6)|(1<<DDD7)|(1<<DDD4);
 //PORTD = (1<<SDA)|(1<<SCL)|(1<<PORTD4); 
 PORTD = (1<<SDA)|(1<<SCL);
 //USART_transmit(DDRD);
 //USART_transmit(PORTD);
 _delay_ms(10);
 PORTD |= (1<<SCL);
 //_delay_ms(10000);
 //USART_transmit(PIND);
 _delay_ms(10);
 //USART_transmit(PIND);
 if(~(PIND)&(1<<SDA)){
 ack = 0;}
 _delay_ms(10);
 //USART_transmit(PIND);
 PORTD |= (1<<SCL);
 _delay_ms(10);
 //USART_transmit(PIND);
 PORTD = (0<<SCL);
 _delay_ms(10);
 //USART_transmit(PIND);
 //set pin6 to output
 DDRD = (1<<DDD6)|(1<<DDD7)|(1<<DDD4);
 PORTD = (1<<SDA)|(1<<SCL)|(1<<PORTD4);
 _delay_ms(10);
 //USART_transmit(DDRD);
 //USART_transmit(PORTD);
 //USART_transmit('a');
 return ack;
}




void USART_init(unsigned int ubrr){
 UCSR0B = (1<<TXEN0)|(1<<RXEN0);

//choose asynchronous mode
 UCSR0C = 0;
 UCSR0C = (0<<UMSEL01)|(0<<UMSEL00);
 UCSR0C |= (1<<UCSZ01)|(1<<UCSZ00);
 UCSR0C |= (1<<USBS0);
 /*//setting UBRR TO 103 for 9600 baudrate
 UBRR0H = 0;
 UBRR0L = 0b01100111; */
 UBRR0H = (unsigned char)(ubrr>>8);
 UBRR0L = (unsigned char)ubrr;
}

void USART_transmit(char data){
 char temp='a';//initialize to a certain character
 //while(temp){
 //temp = *(data++);//go through each character one by one until all the data has been put out
 while( !(UCSR0A & (1<<UDRE0)) ) //
 ;
 //UDR0 = temp;
 UDR0 = data;
 //}
 _delay_ms(10);
}

unsigned char USART_recieve(void){
 /*wait for data to be recieved, this is important because the data register has to get filled up and a flag gets created when a stop bit is set high*/
 while(!(UCSR0A & (1<<RXC0) ))
 ;
 //once the stop bit is set high then read directly from UDRN
 return UDR0;
}

Bot the C code and sketch worked and were able to stop at the appropriate address, which was great. Great exercise, but took a while to get things started. I would really recommend the approach I took, which was to start with sketch and then go to C code because it atleast makes sure if your logic is right. Here is the code to convert from integer to binary as a separate C program, because I like breaking things down and then combining them.

binconv.c

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

void convert_to_binary(int num,char binstr[9]);

int main(){
 int i = 0;
 char binstr[9]= "00000000";
 int pt1=20;int pt2=33;
 //for(i=0;i<128;i++){
 printf("\n20\n");
 convert_to_binary(pt1,binstr);
 printf("Bin Str: %s\n",binstr);
 printf("\n33\n");
 char binstr1[9]= "00000000"; 
 convert_to_binary(pt2,binstr);
 printf("Bin Str: %s\n",binstr);
 printf("\n");
 //}
}

void convert_to_binary(int num, char binstr[9]){
 char temp[9] = "00000000";
 int rem=0;
 int quotient = 0;
 int idx = 7;
 while(num/2!=0){
 rem = num%2;
 num=num/2;
 printf("quotient: %d\n",num);
 printf("rem: %d\n",rem);
 printf("char: %c\n",(char)rem+'0');
 temp[idx] = (char)(rem+'0');
 idx--;
 }
 
 rem = num%2;
 temp[idx] = (char)(rem+'0');
 printf("rem: %d\n",(char)rem);
 printf("char: %c\n",(char)(rem+'0'));
 strncpy(binstr,temp,9);
}
That’s all folks! Let me know if you have any questions! My code can be found on my github. Here are a list of my useful links:
Advertisements

UART on arduino uno in C

 

This has been an information dump, I am trying to write out everything that I have been doing for a past couple of weeks. This post  is on USART which stands for Universal Synchronous/Asynchronous Receiver and Transmitter (I will be focusing on UART), which is used to communicate arduino uno with my computer. There is a great explanation of UART works from circuit basics. Why do I want to communicate with my computer? As your programs get sufficiently complex, it becomes harder and harder to debug the code because there are so many things that can go wrong and it is nice to have print statements that tell you the state of a variable (I do this a lot). In order to get up and running I had to learn how to use, USART because you might not always have a debugger handy. I will walk through the code to help everyone understand what I did.

#include<stdlib.h>
#include<stdio.h>
#include<avr/interrupt.h>
#include<avr/io.h> 
#include<util/delay.h>

#define FOSC 16000000 
#define BAUD 9600
#define MYUBRR FOSC/16/BAUD-1 
//#define MYUBRR 103

void USART_init(unsigned int ubrr);
void USART_transmit(char data);
unsigned char USART_recieve(void);

int main(){
 char data;//"Hello!";
 USART_init(MYUBRR);
 while(1){
 //USART_transmit(97);
 data = USART_recieve();
 USART_transmit(data);
 //_delay_ms(1000);
}
}

void USART_init(unsigned int ubrr){
 UCSR0B = (1<<TXEN0)|(1<<RXEN0);

//choose asynchronous mode
 UCSR0C = 0;
 UCSR0C = (0<<UMSEL01)|(0<<UMSEL00);
 UCSR0C |= (1<<UCSZ01)|(1<<UCSZ00);
 UCSR0C |= (1<<USBS0);
 /*//setting UBRR TO 103 for 9600 baudrate
 UBRR0H = 0;
 UBRR0L = 0b01100111; */
 UBRR0H = (unsigned char)(ubrr>>8);
 UBRR0L = (unsigned char)ubrr;
}

void USART_transmit(char data){
 char temp='a';//initialize to a certain character
 //while(temp){
 //temp = *(data++);//go through each character one by one until all the data has been put out
 while( !(UCSR0A & (1<<UDRE0)) ) //
 ;
 //UDR0 = temp;
 UDR0 = data;
 //}
}

unsigned char USART_recieve(void){
 /*wait for data to be recieved, this is important because the data register has to get filled up and a flag gets created when a stop bit is set high*/
 while(!(UCSR0A & (1<<RXC0) ))
 ;
 //once the stop bit is set high then read directly from UDRN
 return UDR0;
}

The program is simple, you have first initialize the USART and then I am sending data to USART which then gets sent back to make sure the code works.

The first part is initializing the USART which is explained by the USART_init function which is in section 20.5 of the ATMEGA328P manual. The code is a copy of:

Screenshot from 2017-09-03 13:06:41

void USART_init(unsigned int ubrr){
 UCSR0B = (1<<TXEN0)|(1<<RXEN0);

//choose asynchronous mode
 UCSR0C = 0;
 UCSR0C = (0<<UMSEL01)|(0<<UMSEL00);
 UCSR0C |= (1<<UCSZ01)|(1<<UCSZ00);
 UCSR0C |= (1<<USBS0);
 /*//setting UBRR TO 103 for 9600 baudrate
 UBRR0H = 0;
 UBRR0L = 0b01100111; */
 UBRR0H = (unsigned char)(ubrr>>8);
 UBRR0L = (unsigned char)ubrr;
}

One of the first things you are supposed to do is set the baud rate, but what I did instead is setup the pins to transmit and receive. The next step I did was choose if are going to run in synchronous mode or asynchronous mode, and for the purpose of this post I chose asynchronous mode. I chose asynchronous mode because I was just trying get things up and running. There is a great post on EDN that explains the difference between UART and USART (it essentially boils down to the fact that USART has everything synchronized to a clock so it can run at higher baud rates). I chose it to be asynchronous by setting UMSEL01 and UMSEL00 to 0. Once that was completed I defined the size of the stop bit (done by setting the line to high) and I did it for 2 bits (don’t really fully comprehend why this matters, but it seems to be related to running at higher baud rates) by setting UCSZ01 AND UCSZ00 to both 1. The next step was to have no parity bit, basically it means there is no error checking to make sure the data was sent properly. This is outlined in p.194 of the ATMEGA32P manual. Once that was completed I chose a baud rate to run at and placed that value into 2 8bit registers. Once this was completed I moved onto receive and transmitting data:

void USART_transmit(char data){
 char temp='a';//initialize to a certain character
 //while(temp){
 //temp = *(data++);//go through each character one by one until all the data has been put out
 while( !(UCSR0A & (1<<UDRE0)) ) //
 ;
 //UDR0 = temp;
 UDR0 = data;
 //}
}

unsigned char USART_recieve(void){
 /*wait for data to be recieved, this is important because the data register has to get filled up and a flag gets created when a stop bit is set high*/
 while(!(UCSR0A & (1<<RXC0) ))
 ;
 //once the stop bit is set high then read directly from UDRN
 return UDR0;
}

Yes, I noticed that I misspelled receive. The code is simple for transmit, the first that happens before sending the data we wait to see if in the register UCSR0A or USART Control and Status Register UDRE0 is set to 1. If it set to one that means the buffer is ready to be written to.

screenshot-from-2017-09-03-140700.png

UDR0 is only written to once UDRE0 flag is set to 1 otherwise the buffer still have data in it. The receive function does exactly the same, but instead of writing to UDR0 it read from UDR0 as outline by

screenshot-from-2017-09-03-141137.png

It reads in the data from UDR0 only when RXC0 flag is set. You can see it working by doing the following, first set up minicom with the -s flag and then go to “Serial por setup” and then choose the device that is your uno, and the choose the communication parameters which is under “Bps/Par/Bits” and choose current to be 9600N2 where 9600 is the baud rate N is no parity bit and 2 means 2 stop bits and then I hit “Exit” NOT “Exit from Minicom”. In another terminal I would type

user@user-Bonobo-Extreme:~/git-repos/arduino/arduino_uno/manual_I2C$ ls /dev/ttyACM0 
/dev/ttyACM0
user@user-Bonobo-Extreme:~/git-repos/arduino/arduino_uno/manual_I2C$ echo "a" > /dev/ttyACM0

and when you look at the minicom terminal you should see an “a” character pop up

Welcome to minicom 2.7

OPTIONS: I18n 
Compiled on Jan 1 2014, 17:13:19. 
Port /dev/ttyACM0, 14:20:08 
 
Press CTRL-A Z for help on special keys 
 
a

which it does! So there you go. The code can be found on my github.

As always here is a list of my useful links:

http://www.edn.com/electronics-blogs/embedded-basics/4440395/USART-vs-UART–Know-the-difference

http://www.unm.edu/~zbaker/ece238/slides/UART.pdf

http://www.circuitbasics.com/basics-uart-communication/

https://learn.sparkfun.com/tutorials/serial-communication/rules-of-serial

Using ISR on arduino uno in C

This will be about how to use ISR(interrupt service request) in arduino uno. The code will trip a ISR which means once the ISR is tripped, the code stops and executes the ISR and then moves on. I used header files again for the timers and then wrote code that works with the ISR.
The header file is defined as follows:

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

//Register variables

#define OCR1AL_reg (*(volatile unsigned char *)(0x88)) //output compare low 8 bits for Counter 1
#define OCR1AH_reg (*(volatile unsigned char *)(0x89)) //output compare high 8 bits for Counter 1

#define TCCR1B_reg (*(volatile unsigned char *)(0x81)) //Timer/Counter0 Control Register B 
#define TCCR1A_reg (*(volatile unsigned char *)(0x80)) //Timer/Counter0 Control Register A

#define TIMSK1_reg (*(volatile unsigned char *)(0x6F)) //Timer/Counter0 Interrupt Mask Register

#define TIFR1_reg (*(volatile unsigned char *)(0x36)) //Timer/Counter0 Interrupt Flag Register

#define TCNT1H_reg (*(volatile unsigned char *)(0x85)) //Timer/Counter0 Interrupt Flag Register
#define TCNT1L_reg (*(volatile unsigned char *)(0x84)) //Timer/Counter0 Interrupt Flag Register

//setting up PBn
#define DDRB_reg (*(volatile unsigned char *)(0x24)) //Sets up the DDR for B
#define PORTB_reg (*(volatile unsigned char *)(0x25)) //sets up port B
#define PINB_reg (*(volatile unsigned char *)(0x23)) //to be able to read PINB
#define PCICR_reg (*(volatile unsigned char *)(0x68))

//setting up the global interrupt register
#define SREG_reg (*(volatile unsigned char *)(0x5F)) //Status register used for disabling and enabling global interrupts

#define FCLK_atmega32u4 8000000 //clock speed

//setting up TCCR1A control register
int COM1A1_val = 7;//0b10000000;
int COM1A0_val = 6;//0b01000000;
int COM1B1_val = 5;//0b00100000;
int COM1B0_val = 4;//0b00010000;
int COM1C1_val = 3;//0b00001000;
int COM1C0_val = 2;//0b00000100;
int WGM11_val = 1;//0b00000010;
int WGM10_val = 0;//0b00000001;

//setting up TCCR1B control register
int ICNC1_val = 7;//0b10000000;
int ICES1_val = 6;//0b01000000;
int WGM13_val = 4;//0b00010000;
int WGM12_val = 3;//0b00001000;
int CS12_val = 2;//0b00000100;
int CS11_val = 1;//0b00000010;
int CS10_val = 0;//0b00000001;


int Bit_0 = 0;
int Bit_1 = 1;
int Bit_2 = 2;
int Bit_3 = 3;
int Bit_4 = 4;
int Bit_5 = 5;
int Bit_6 = 6;
int Bit_7 = 7;

//setting up TIMSK1 register
int OCIE1A_val = 1;
int ICIE1_val = 5;

//unsigned char prescale_8 = CS11_val;
//unsigned char prescale_64 = CS10_val|CS11_val;
//unsigned char prescale_256 = CS12_val;
//unsigned char prescale_1024= CS12_val|CS10_val;

The time the code is done slightly differently where I have assigned int values to the bits instead of binary values, this allows me to do (1<<Bit_0). You can see that it is pretty similar to the header file in my previous post. I will start talking about to use the ISR and how the timers are being set up.

#include "arduino_pin_header.h"
#include<stdio.h>
#include<stdlib.h>
#include<avr/interrupt.h>

int x = 0;

int main(){

DDRB_reg = 0;
 PORTB_reg = 0;
 DDRB_reg = (1<<Bit_5);
 PORTB_reg = (0<<Bit_5);

//resetting the Timer/Counter1
 TCNT1H_reg = 0;
 TCNT1L_reg = 0; 
 
 //disabling all global interrupts
 SREG_reg = 0;

//defining prescalar

//TCCR1B: ICNC1 ICES1 – WGM13 WGM12 CS12 CS11 CS10
 TCCR1B_reg = 0;
 //TCCR1B_reg = CS11_val; WORKING SETTINGS
 TCCR1B_reg = (1<<CS10_val)|(0<<CS12_val);//0b00000101;//(1<<CS10_val)|(1<<CS12_val);

//setting up PWM mode

//TCCR1A: COM1A1 COM1A0 COM1B1 COM1B0 COM1C1 COM1C0 WGM11 WGM10
 TCCR1A_reg = 0; //this is for waveform generation and CTC setting up mode;
 TCCR1A_reg = (1<<COM1A1);//0b10000000;//(1<<COM1A1_val);
 //TCCR1A_reg = COM1A1_val|WGM10_val; //this is for waveform generation and CTC setting up mode; WORKING SETTINGS

//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
 //100Hz = 10011 10001000
 //10kHz = 110010
 //100kHz = 
 // (*(volatile unsigned char *)(OCR1AH_reg)) = Bit_3|Bit_2|Bit_1|Bit_0;//0b00001111; //writing to high first which will write to a temp register first
 //OCR1AH_reg = 0;//0b0001100;//0b00001111; //writing to high first which will write to a temp register first
 // (*(volatile unsigned char *)(OCR1AL_reg)) = Bit_6|Bit_1;//0b01000010; //writing to low will write both high and low in the same clock cycle
 //OCR1AL_reg = 0b11001110;//0b01000010; //writing to low will write both high and low in the same clock cycle DEFAULT WORKING SETTINGS
 //OCR1AL_reg = 0b00000101;

OCR1AH_reg = 0b10011100;//0b00000000;
 OCR1AL_reg = 0b01000000;//0b01000000;
 
 TIMSK1_reg = (1<<OCIE1A_val)|(1<<ICIE1_val);//0b00100010;//(1<<ICIE1_val)|(1<<OCIE1A_val);//0b00100010; //writing so that output compare A is set up

//enable global interrupts
 SREG_reg = (1<<Bit_7);
 while(1){}
 return 0;

}

ISR(TIMER1_COMPA_vect){
 
 PORTB_reg = PORTB_reg^(1<<Bit_5);
}

Now you can see a new thing pop up which is ISR(TIMER1_COMPA_vect). I am using Bit 5 because then I can just watch the LED get toggled.

DDRB_reg = 0;
 PORTB_reg = 0;
 DDRB_reg = (1<<Bit_5);
 PORTB_reg = (0<<Bit_5);

//resetting the Timer/Counter1
 TCNT1H_reg = 0;
 TCNT1L_reg = 0; 
 
 //disabling all global interrupts
 SREG_reg = 0;

The first part of the code sets DDRB as output and sets PORTB to 1 which will then set up the LED for the pin or can be used to output to that pin. At the same time, timer1 is set to 0 and all global interrupts are disabled so the code doesn’t stall if the uC suddenly gets an interrupt.

//TCCR1B: ICNC1 ICES1 – WGM13 WGM12 CS12 CS11 CS10
 TCCR1B_reg = 0;
 //TCCR1B_reg = CS11_val; WORKING SETTINGS
 TCCR1B_reg = (1<<CS10_val)|(0<<CS12_val);//0b00000101;//(1<<CS10_val)|(1<<CS12_val);

//setting up PWM mode

//TCCR1A: COM1A1 COM1A0 COM1B1 COM1B0 COM1C1 COM1C0 WGM11 WGM10
 TCCR1A_reg = 0; //this is for waveform generation and CTC setting up mode;
 TCCR1A_reg = (1<<COM1A1);//0b10000000;//(1<<COM1A1_val);

The next step is the prescalar which I described in my previous post and the table for it is show below (found on p.134):

Screenshot from 2017-09-03 02:25:49

This is being set in Counter Register B. The next step sets ups TCCR1A. The first part is setting the TCCR1A to normal setting as shown in the table below:

Screenshot from 2017-09-03 00:42:16

You can see when the mode is set to the the Timer/Counter Mode operation is set to 0 so it is not doing any Phase correction and things like that. What I do set is COM1A1, and this sets up the pins so that in normal mode the normal behavior of PinB5 is taken over by the timer.

Screenshot from 2017-09-03 02:31:33

When COM1A1 is set the the 0C1A is cleared when the timer counts a certain level and the output is set to low. So all this is doing is making OC1A go low.

 OCR1AH_reg = 0b10011100;//0b00000000;
 OCR1AL_reg = 0b01000000;//0b01000000;

This just sets the limit at which the timer will count to until clearing OC1A in this case (or setting OC1A low or digitally think of it being set to 0).

TIMSK1_reg = (1<<OCIE1A_val)|(1<<ICIE1_val);//0b00100010;//(1<<ICIE1_val)|(1<<OCIE1A_val);//0b00100010; //writing so that output compare A is set up

//enable global interrupts
 SREG_reg = (1<<Bit_7);
 while(1){}
 return 0;

The next major line is the TIMSK1_reg which sets up the Timer interrupt mask register and sets up the interrupts that we are interested in with the global interrupts. This sets up interrupts to be enabled on OCIE1A (links up with OC1A pin). It also sets up ICIE1 which sets up input interrupt (meaning an input signal will trip the start of an interrupt. Since we are setting up these interrupts we don’t want to trip an interrupt while you are setting things up to avoid race conditions. So we enable global interrupts to get everything going.

screenshot-from-2017-09-03-024751.png

screenshot-from-2017-09-03-024805.png

The while loop near the end of the main() is very important. What would happen is in the PWM case I don’t need to put the while loop because the timer will keep working independently and gets set once. In the case of the interrupts, the timer has to keep running and every time the interrupt gets called it has to look back on the code but if the code has exited that function has gone away, so it was important to have the while loop at the end or the ISR might only get tripped at all or never at all.

ISR(TIMER1_COMPA_vect){

PORTB_reg = PORTB_reg^(1<<Bit_5);
}

The ISR code is only gets tripped when the OCIE1A is set and it sends it to the ISR function (I would think of it more of a macro). When the ISR we can define which interrupt will cause what behavior and in this case an ISR generated by TIMER1_COMPA_vect will cause PinB5 to get toggled high or low based on its previous state. Finding the right variable that goes with the OC1A took a while but can be found here. The annoying thing about finding those interrupt vectors, is that they are not very obvious. But in short timer gets started –> hits the threshold –> creates an interrupt flag –> sends it to the ISR –> ISR check what caused the request –> sends it directly to the predefined function. I have been told not to spend too much time in ISR because it can create a backlog very quickly.

Here are the links I found useful:

http://www.avrbeginners.net/architecture/timers/timers.html

http://ee-classes.usc.edu/ee459/library/documents/avr_intr_vectors/

My code can be found in my git repo and the name of the c file is ISR_example.c

 

PWM with TIMER1 on arduino uno

Tried to create a PWM with TIMER1 on arduino uno. This was done merely to get an understanding of how to use timers in arduino uno, which should be similar to the SparkFun ProMicro. I will try to go through all the steps as best as I can. I started doing this directly in C, which if you are a beginner like me and don’t want to get specialized to tools to debug issues, I would not recommend using. I would recommend going from sketch and then to C to make sure that your logic makes sense. Let’s start with the header file:

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




//Register variables

#define OCR1AL_reg (*(volatile unsigned char *)(0x88)) //output compare low 8 bits for Counter 1
#define OCR1AH_reg (*(volatile unsigned char *)(0x89)) //output compare high 8 bits for Counter 1

#define TCCR1B_reg (*(volatile unsigned char *)(0x81)) //Timer/Counter0 Control Register B 
#define TCCR1A_reg (*(volatile unsigned char *)(0x80)) //Timer/Counter0 Control Register A

#define TIMSK1_reg (*(volatile unsigned char *)(0x6F)) //Timer/Counter0 Interrupt Mask Register

#define TIFR1_reg (*(volatile unsigned char *)(0x36)) //Timer/Counter0 Interrupt Flag Register

#define TCNT1H_reg (*(volatile unsigned char *)(0x85)) //Timer/Counter0 Interrupt Flag Register
#define TCNT1L_reg (*(volatile unsigned char *)(0x84)) //Timer/Counter0 Interrupt Flag Register

//setting up PBn
#define DDRB_reg (*(volatile unsigned char *)(0x24)) //Sets up the DDR for B
#define PORTB_reg (*(volatile unsigned char *)(0x25)) //sets up port B
#define PINB_reg (*(volatile unsigned char *)(0x23)) //to be able to read PINB
#define PCICR_reg (*(volatile unsigned char *)(0x68))

//setting up the global interrupt register
#define SREG_reg (*(volatile unsigned char *)(0x5F)) //Status register used for disabling and enabling global interrupts

#define FCLK_atmega32u4 8000000 //clock speed




//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;




unsigned char Bit_0 = 0b00000001;
unsigned char Bit_1 = 0b00000010;
unsigned char Bit_2 = 0b00000100;
unsigned char Bit_3 = 0b00001000;
unsigned char Bit_4 = 0b00010000;
unsigned char Bit_5 = 0b00100000;
unsigned char Bit_6 = 0b01000000;
unsigned char Bit_7 = 0b10000000;

//unsigned char prescale_8 = CS11_val;
//unsigned char prescale_64 = CS10_val|CS11_val;
//unsigned char prescale_256 = CS12_val;
//unsigned char prescale_1024= CS12_val|CS10_val;

I made this header file so that I don’t have to use any of the arduino libraries. This was more of a learning experience for me to understand how the registers are used and how the values are set on those register. You can see the register are defined as “volatile” and are after #define to make it easier for me to understand, look at my earlier blog post to understand what the volatile and then dereferencing it. The next set of unsigned char basically assign different values on the registers. These value setup the register to run in different modes which is especially important for setting up pins to work with timers. The next set of code shows how the timers is being created and PWMs are being set-up.

#include "arduino_pin_header.h"
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>

void setOCRnxRegisters(unsigned int OCnumber);
void setPWMFrequency(double PWMFrequency);

int main(){

 DDRB_reg = 0;
 PORTB_reg = 0;
 DDRB_reg = Bit_1;
 PORTB_reg = Bit_1;

//resetting the Timer/Counter1
 TCNT1H_reg = 0;
 TCNT1L_reg = 0; 
 
 //disabling all global interrupts
 SREG_reg = 0;

//defining prescalar

//TCCR1B: ICNC1 ICES1 – WGM13 WGM12 CS12 CS11 CS10
 TCCR1B_reg = 0;
 //TCCR1B_reg = CS11_val; WORKING SETTINGS
 TCCR1B_reg = WGM13_val;

//setting up PWM mode

//TCCR1A: COM1A1 COM1A0 COM1B1 COM1B0 COM1C1 COM1C0 WGM11 WGM10
 TCCR1A_reg = 0; //this is for waveform generation and CTC setting up mode;
 TCCR1A_reg = WGM10_val|COM1A0_val;
 //TCCR1A_reg = COM1A1_val|WGM10_val; //this is for waveform generation and CTC setting up mode; WORKING SETTINGS

//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
 //100Hz = 10011 10001000
 //10kHz = 110010
 //100kHz = 
 // (*(volatile unsigned char *)(OCR1AH_reg)) = Bit_3|Bit_2|Bit_1|Bit_0;//0b00001111; //writing to high first which will write to a temp register first
 //OCR1AH_reg = 0;//0b0001100;//0b00001111; //writing to high first which will write to a temp register first
 // (*(volatile unsigned char *)(OCR1AL_reg)) = Bit_6|Bit_1;//0b01000010; //writing to low will write both high and low in the same clock cycle
 //OCR1AL_reg = 0b11001110;//0b01000010; //writing to low will write both high and low in the same clock cycle DEFAULT WORKING SETTINGS
 //OCR1AL_reg = 0b00000101;

setPWMFrequency(100000);

TIMSK1_reg = 0;//0b00100010; //writing so that output compare A is set up

//enable global interrupts
 SREG_reg = Bit_7;

return 0;

}


void setPWMFrequency(double PWMFrequency){
 //focn = fclk/(2*N*TOP) where N is the prescalar
 //TOP = fclk/(2*N*focn)
 printf("Frequency of interest is %.2f\n",PWMFrequency);
 //defining a bunch of prescalars
 int prescalar[5] = {1,8,64,256,1024};
 unsigned char prescalers[5]= {CS10_val,CS11_val,CS10_val|CS11_val,CS12_val,CS12_val|CS10_val};

int x = 0;
 unsigned int OCnumber=0;
 for(x=0;x<5;x++){
 OCnumber = FCLK_atmega32u4/(2*prescalar[x]*PWMFrequency);
 if(OCnumber <= pow(2,16)-1){
 printf("The OC number is %d\n",OCnumber);
 TCCR1B_reg |= prescalers[x];
 printf("Prescalar chose is %d\n",prescalers[x]);
 
 break;
 }
 }
 setOCRnxRegisters(OCnumber); 
}

void setOCRnxRegisters(unsigned int OCnumber){
 //convert a 16bit number into 2 8 bit numbers
 uint8_t binarylow = OCnumber & 0xff;
 uint8_t binaryhigh = (OCnumber >> 8);
 OCR1AH_reg = binaryhigh;
 OCR1AL_reg = binarylow;
}

The first thing we want to note according to p.82 of the ATMEGA328p manual PB1 is linked to the OC1A (Timer1/Counter1 Output Compare Match A Output).

 DDRB_reg = 0; 
 PORTB_reg = 0; 
 DDRB_reg = Bit_1; 
 PORTB_reg = Bit_1;

When looking at p.83 of the  it shows that in order to use OC1A we have to set PB1 to output hence required DDRB1 and PORTB1 be set to 1.

//resetting the Timer/Counter1
 TCNT1H_reg = 0;
 TCNT1L_reg = 0; 
 
 //disabling all global interrupts
 SREG_reg = 0;

//defining prescalar

//TCCR1B: ICNC1 ICES1 – WGM13 WGM12 CS12 CS11 CS10
 TCCR1B_reg = 0;
 //TCCR1B_reg = CS11_val; WORKING SETTINGS
 TCCR1B_reg = WGM13_val;


//setting up PWM mode

//TCCR1A: COM1A1 COM1A0 COM1B1 COM1B0 COM1C1 COM1C0 WGM11 WGM10
 TCCR1A_reg = 0; //this is for waveform generation and CTC setting up mode;
 TCCR1A_reg = WGM10_val|COM1A0_val;

Timer1 is constantly counting and we don’t want it to hit the threshold we are interested in so in order to avoid that we start timer1 at 0 and at the same time remove all interrupts. We disable interrupts, because if we didn’t do that, it would cause the uC to finish the interrupt before moving on to the next step. The next step was setting up the Timer/Counter Register 1A and 1B, to define the timer behavior. The first step is to define how the waveform will work which is set by WGM13 and WGM10 which is in page 132 of the ATMEGA32P manual. The sets the PWM with Phase and Frequency correct(I am not sure of all the differences yet, but it seems to work) or mode 9. The TOP is set by OCR1A which means when the counter hits a certain threshold then it will output to that OCR1A pin.

screenshot-from-2017-09-03-004216.png

Screenshot from 2017-09-03 00:45:57

Table 16-3 defines that when the counter hits the a compare level then it will toggle OC1A when the WGM13:0 = 9 or (mode 9) which is what we are using. So the waveform in mode 9 will cause OC1A to toggle.

 setPWMFrequency(100000);

This goes to the following function:

void setPWMFrequency(double PWMFrequency){
 //focn = fclk/(2*N*TOP) where N is the prescalar
 //TOP = fclk/(2*N*focn)
 printf("Frequency of interest is %.2f\n",PWMFrequency);
 //defining a bunch of prescalars
 int prescalar[5] = {1,8,64,256,1024};
 unsigned char prescalers[5]= {CS10_val,CS11_val,CS10_val|CS11_val,CS12_val,CS12_val|CS10_val};

int x = 0;
 unsigned int OCnumber=0;
 for(x=0;x<5;x++){
 OCnumber = FCLK_atmega32u4/(2*prescalar[x]*PWMFrequency);
 if(OCnumber <= pow(2,16)-1){
 printf("The OC number is %d\n",OCnumber);
 TCCR1B_reg |= prescalers[x];
 printf("Prescalar chose is %d\n",prescalers[x]);
 
 break;
 }
 }
 setOCRnxRegisters(OCnumber); 
}

void setOCRnxRegisters(unsigned int OCnumber){
 //convert a 16bit number into 2 8 bit numbers
 uint8_t binarylow = OCnumber & 0xff;
 uint8_t binaryhigh = (OCnumber >> 8);
 OCR1AH_reg = binaryhigh;
 OCR1AL_reg = binarylow;
}

The first step is to create a prescalar which can be explained in a very simple way. Let’s say a clock moves at a certain frequency, it moves 1 tick per second. The fastest the clock the can move is 1 tick per second. Now let’s say you want to count 10s as 1 time unit for another application. The prescalar essentially says that 10 ticks at 1 ticks per second will count for 1 time unit. There are multiple different prescalars based on how low of a frequency you want to count at. These are done by prescalars array. The for loops goes through every prescalar and tries to figure out which prescalar can be used.

OCnumber = FCLK_atmega32u4/(2*prescalar[x]*PWMFrequency);

This is based on p.128 of the ATMEGA328p manual:

Screenshot from 2017-09-03 00:58:55

All I did was move over and TOP and solved for it which resulted in a OCnumber. Since I only get 2^16 bits to work with I need to make sure my OCnumber doesn’t go beyond that, which is done by:

OCnumber <= pow(2,16)-1

If this is true then the prescalar gets set by doing

TCCR1B_reg |= prescalers[x];

The next part of the code basically splits the up 16 bit counter value into two 8bit registers. Remember you have to right to the high byte first and then to the low because when you write to low it writes to both high byte and low byte simultaneously (this is because first writing to the high byte stores it in a temporary register.

TIMSK1_reg = 0;//0b00100010; //writing so that output compare A is set up

//enable global interrupts
 SREG_reg = Bit_7;

The mask is then turned off so that the PWM can work and then enabling global interrupts to go back to business as usual.

Here are some useful link(s) I found:

https://paritycheck.wordpress.com/2009/03/27/what-does-this-mean-volatile-unsigned-char-0x22/

My code can be found at my github.

Toggling a pin in C on the Arduino uno

It has been a while since I have posted, mainly because I have been trying to get to a stopping point, where I could just spend a few days writing. I switched over the arduino uno, mainly because of the issues I have outlined (I loose connecting to the computer as soon as the sparkfun micro gets up and running). I decided to start from scratch and work on the basics and then went up from there. So the first thing I started with was trying to blink an led on the arduino uno. The code is very similar to sparkfun micro. In order to upload my code onto arduino uno I used this link to get me started and then combined it with arduino sketch output. I ended up with the following script

avr-gcc -Os -DF_CPU=16000000UL -mmcu=atmega328p -c -o blink.o blink.c
avr-gcc -mmcu=atmega328p blink.o -o blink
avr-objcopy -O ihex -R .eeprom blink blink.hex

#flashing the Arduino:
#avrdude -V -F -C /etc/avrdude/avrdude.conf -p atmega328p -P /dev/ttyUSB0 -c stk500v1 -b 57600 -U flash:w:blink.hex
avrdude -C/home/ashwini/Downloads/arduino-1.8.3/hardware/tools/avr/etc/avrdude.conf -v -patmega328p -carduino -P/dev/ttyACM0 -b115200 -D -Uflash:w:blink.hex:i

I was able to compile and upload to the uno using the software above. Information from Balau’s website was instrumental in getting me started on the uno. The C code for blinking an led was:

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

int main (void)
{
 /* set PORTB for output*/
 DDRB = 0xFF;

while (1)
 {
 /* set PORTB.5 high */
 PORTB = 0x20;

_delay_ms(200);

/* set PORTB.5 low */
 PORTB = 0x00;

_delay_ms(200);
 }

return 1;
}

This allowed me to blink an led. I have stepped away from using my own header file because it became quite a pain in the neck to carry around those header files and plus I need to figure out how to link up the header files (which needs to happen as my projects get more complex). Looking at the arduino website, the led pin seems to be on what is defined as D13. After looking at the schematic , the Pin 13 is found on PB5. This can be found here:Screenshot from 2017-09-02 14:13:03

As you can see D13 or SCK is also found on PB5. Once you toggle that pin correctly you should be able to see led toggle.

 

Here is the list of the useful links I used:
https://github.com/dataplayer/Blinking-LED-on-Arduino

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

https://www.arduino.cc/en/Tutorial/Blink

My code can be found on github.

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