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.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s