Moving Beyond Arduino Part 3

At this point you have working code, an LED that you can control and hopefully a better understanding of how to work with a microcontroller.  But there’s still a lot to cover so lets talk about the elephant in the room… your code.  First off, learning how exactly your code is doing what you want and whether it’s doing it in the best way possible (spoiler: it’s not).

Fair warning this is going to be a longer post with a lot of code.

I’m going to skip over basics like, what are variables and things like binary and hex.  I’m assuming you’ve come from the Arduino environment which should have exposed you to those things.

#define (and no it’s not a trending Twitter hashtag)

So let’s start with the first part the #define line.  What does it do?

#define LED_DIR       ((uint8_t *) 0x24)

I said before you could think of a #define like a variable, like int a = 5.  That’s not really true but for the last example it was close enough.  Really it’s a macro and it’s more like a placeholder than a variable.  For example:

//Define NUM1
#define NUM1 5 

//Define variable a
int a = 0;

int main(void) {
  a = NUM1 + 2;  //a will equal 7
  a = 5 + 2; //same as the previous line but we wrote out 5 here
}

You might look at this and say, “OK I see the use there but why use a #define and not just a variable?”.  A valid question, and you might ask “Also that looks a lot like a variable to me”.  Another valid point.  Lets look at some more examples where they start to diverge.

#define NUM1 5 + 2

//Define variable a
int a = 0;

int main(void) {
 a = NUM1 + 2; //a will equal 9 (same as 5 + 2 + 2)
 a = NUM1*2; //a will equal... 9?  Why?
 NUM1 = 4; //This will give an error.
}

First look at our define statement where we say 5+2, if you think of NUM1 as a normal variable then you’ll think that NUM1 = 7, but that’s where things start to diverge.  NUM1 always represents what you put next to it; so it represents 5+2.  The first line of code inside the main function seems normal enough but the second line seems off.  If NUM1 equals 7 wouldn’t a = 14?  No, because NUM1 doesn’t represent 7 it represents 5 + 2, so wherever you put a NUM1 it replaces that value with 5+2.  So really what the compiler sees is a = 5 + 2 * 2.  So 2*2 = 4, then plus 5 you get 9.

This is where things can get tricky and confusing.  It’s why you’ll usually always see define values with () around them like the following code.

#define NUM1 (5 + 2)

Now it would be a = (5 + 2)*2, which is 14.

Hopefully you’ll see why now NUM1 = 4 is also not valid.  It’s not a variable, it’s just a placeholder that’s more like a constant.

So that’s all well and good but why use them?  Well for one thing it’s easier to write small pieces of code that couldn’t be variables which we’ll see later on.  Sometimes it’s just preference as whether you want something as a variable or as a #define.

While we’re talking about defines I’ll show another example that show a use case that can be handy for simple pieces of code.

//The following code almost acts like a function
#define NUM1(x) (x + 2) 

int a = 0;

int main(void) {
  a = NUM1(3); //As you guess this equals 5 but remember this isn't a function
              //This is a placeholder so it's not "returning" 5 but putting
              //the following in it's place: (3 + 2).
}

Pointers

Now lets talk easily the most important part of this lesson today.  Pointers.

To sum up a pointer in the most basic terms, it’s used to “point” to an address.  To get a basic understanding I suggest you use a C compiler on your computer to test out code.  There are ones available via your web browser so you don’t even have to download anything.  I’m using the following (https://www.tutorialspoint.com/compile_c_online.php)

Now here’s the standard use of a pointer:

int *p; //This is my pointer declaration
int a = 10; //This is a variable

int main(void) {
 p = &a;      //This says that p should point the address of a
 int b = *p;  //b will equal 10
 b = p;       //b will equal the address of a
 *p = 12;     //This changes the value of a to be 12
}

Pointers are where everyone always gets confused but so long as you understand the fundamentals you’ll be fine.  Syntax can always be looked up remind you how to set things up.  So let’s tackle what’s going on here.

We define pointers using the ‘*’ key.  That says this variable will be a pointer and a pointers value is supposed to be a memory address.  We can assign them manually like we did in the last section (I’ll go into more detail later) or define a variable and point to it using the ‘&’.  The ‘&’ symbol means you want the address of that variable.

Remember everything is stored in memory.  So when you write a=10.  What you’re really saying is go the memory address of ‘a’ and replace it’s value with 10 (0x0A in hex).  So to assign the address of a pointer you simply put the following:

pointer = memory address;

Again we could define the memory address ourselves (0x03) or use the ‘&’ symbol (&someVariable).  To get the value that p is pointing to, use *p.  So if we were using some basic c compiler on your computer or on your web browser, we can test some code.

#include <stdio.h>

int *p;
int a = 10;

//DON"T WORRY ABOUT PRINTF

int main()
{
 p = &a;
 printf("%d\n", &a); //Will print address of a
 printf("%d\n", p);  //Will print the value of p (which is the address of a)
 printf("%d\n", a);  //Will print the value of a, 10
 printf("%d\n", *p); //Will print the value of whatever we're pointing to
                   //in this case 'a', 10.  This is the actual value of 'a'
                   //If you change 'a' the value of *p will change as well
 a = 5;
 printf("%d\n", *p); //Will print 5 now
 
 return 0;
}

You should see a large value when you print ‘p’ or ‘&a’ (that’s the address) but then when you print ‘*p’ or just ‘a’ you get the variable.

So what are these used for?  They provide you the ability to access exact memory addresses which is key for coding a MCU.  Let’s look our previous example from the last section:

#define LED_DIR       ((uint8_t *) 0x24)
#define LED_DATA      ((uint8_t *) 0x25)

int main(void) {
   *LED_DIR = 0x20;
   *LED_DATA = 0x20;
}

The first line we use is our define, to make a pointer that points to 0x24.  It may look different but look at it like this:

int * p; //NOTE: int *p and int * p (with the added space) are the same
((int *) p) //The exact same as the above
((uint8_t *) 0x24) //Now with a static address and uint8_t rather than int

You can see they look similar and in reality what we’re defining is a pointer but rather than one that can change value it’s static at 0x24.  That’s the power of #define.  Sure we can also do int *LED_DIR = 0x24; but I’ll show you something you can’t do with a standard variable.

#define LED_DIR (* ((uint8_t *) 0x24))

What does this do?  Now rather than have *LED_DIR = 0x20 you can just write LED_DIR = 0x20.  Is there a difference as far as end result?  No, but it’s simpler to write and cleaner.  That’s an important lesson in coding that there a lot of different ways of getting the same result.  What matters is it clean/easy to read, easy to update and is it a method you’re comfortable with.

So given what I just wrote we can simply the code to the following:

#define LED_DIR    (*((uint8_t *) 0x24))
#define LED_DATA   (*((uint8_t *) 0x25))

int main(void) {
   LED_DIR = 0x20;
   LED_DATA = 0x20;
}

Not a major change but one that’ll make your coding a little easier to type out and neater to read.  Of course this begs the question, are we currently writing out our code in way that’s easy to modify or change later than?  The short answer is no.  Right now you have to memorize, or always look up, what your register does every time you come back to this code.  For LED_DIR and LED_DATA it’s easy since it’s just defining direction and data.  You could simply add some comments that say each bit represents a pin on PortB.

You might notice with that last sentence that there’s a problem.  I’ve defined DIR and DATA for only PortB.  Really there DIR and DATA registers for each port, so I need to specify that it’s PortB and name out the rest of the ports.

To add some more information on the #define macro you could rename LED_DIR to PORTB_DIR so you can have different names for various ports.  However, it’s not dynamic.  For example, PORTA and PORTB share the same register types(DIR, DATA, etc) but with different offsets.  So wouldn’t it be nice to just declare them once and just define register offsets?

Also, as registers get more complex they’ll have multiple uses.  Just to keep it simple you could have a register that has bits 0 to 3 as DIR and bits 4 to 7 as DATA.  Unlikely, but you get the idea.  If you don’t remember that register memory allocation you have to look it up all the time.  It’s much easier to put in the work in the beginning so you save a headache later; which is what we will do now using two things Structs and Unions.

Struct

A struct is a way of grouping together information.  Here is an example:

//This defines what the struct will be
struct Shapes {
 int sides;      //An int called sides
 char name[100]; //A char array (aka a string) for the shape name
};

int main(void) {
 struct Shapes shape; //Declares our struct here 
 shape.sides = 3;  //Define the variable sides for this shape
 shape.name = "triangle"; 

 struct Shapes randomName; //Can have multiple Shapes with different values
 randomName.sides = 4;
 randomName.name = "square";
}

You can think of Shapes as a type of variable with different parts.  First you define the struct name and its parts.  Then declare a type of struct almost like any other variable but state it’s a struct prior.  From there you use ‘.’ to get to it’s local variables and assign them values.

Seems simple enough but where does this come into play for us?  We’re going to use a different type of struct called a typedef struct.  That’s to just simplify the use case.

A typedef is used to define a new type of variable, like an int or char.  This along with a struct can be used the following way.

typedef struct {
 volatile  uint8_t DIR;
 volatile  uint8_t DATA;
} PORT_REG;

#define PORTB_REG ((PORT_REG *) 0x24)

Don’t run away, this code is surprisingly easy to understand once you take the time to look at it.  First we’re defining a struct but not just a regular struct, a typedef struct.  You’ll notice there’s no name, that’s because we don’t plan on declaring new structs of these types in the future.

So rather than do what we did before (define a new struct then declare a new one with the following code “struct Shapes shape;”) we define and declare it at the same time.  That’s what that last line in the typedef struct is (PORT_REG).  It’s defining a new struct for us.

Then using our #define and pointer we can take that struct and point it’s first variable to the address 0x24.  Which, coincidentally, is the offset of the DIR register for PortB.  Here’s where this struct really shines.  Since we defined DIR as only 8 bits long, DATA will be the next value over in memory, aka 0x25.  If we made DIR a uint16_t (16 bits long rather than 8) then we would have had DIR start at address 0x24 but also take up the address of 0x25.  Then DATA would have been 0x26.

By writing out our PORT_REG struct properly we’ve made it easy to define specific port register by simply pointing it to the lowest address value and properly sizing each register.  Now if we wanted to do the same thing for PortA (assuming it was the same as PortB in that DIR was first, then DATA, etc) then we could just use:

#define PORTA_REG ((PORT_REG *) 0x2...)

Before moving on to unions, I bet you’re also asking what is volatile?  It lets the compiler know that this register value can change from an outside source.  Why use it?  Here’s a basic example:

int a = 1;

while(a==1) {
}

From a compiler point of view this will loop forever so it’ll replace this check of a==1 with just 1.  But what if ‘a’ is changed by the press of a button outside the MCU?  How would the compiler know that?  If you label it as volatile you’re telling the compiler, “Hey this value can change at anytime so don’t assume you know it’s value”.

The final code would be “volatile int a = 1;”

Unions (minus the giant inflatable rats)

With a little leg work we got more dynamic and easy to work with code.  This doesn’t solve the problem of what happens when a register has bits with different uses.  That’s where we get into unions.  Easiest way to get started is look at our use case:

typedef union { 
 struct { 
     uint8_t PMUXEN:  1; 
     uint8_t INEN:    1; 
     uint8_t PULLEN:  1; 
     uint8_t:         3; 
     uint8_t DVRSTR:  1; 
     uint8_t:         1; 
   }bits; 
   uint8_t reg;
} PORT_CFG;

What is all of this?  First things to make life easier think of a union as a struct but it’s memory footprint is only as big as it’s largest value.  I.e. a struct with 32 different 8bit values in it will bit 8*32 bits long, but a union with 32 different 8bit values will be 8bits long.

Another example is a union with an 8bit variable in it and a 16bit variable in it.  If that was a struct it would be 24bits long but in a union its 16.

So what does this buy us in our case?  It’s easier to show you.

PORT_CFG.bits.PULLEN = 1;
PORT_CFG.reg = 0x00;

Now we can select individual bits and assign them values without affecting the rest of the register.  Which we could do before but you would have to use techniques that aren’t hard to do (OR’ing/XOR’ing values) but isn’t as easy to read.  Now it’s clear as day we’re taking the PULLEN bit of PORT_CFG register and setting it equal to 1.

We also don’t lose the ability to set the value of register in one fell swoop as you can see with the ‘.reg’.  That’s the advantage of the union, and is something we couldn’t do with a struct.

Now that we understand what it does for us, let’s go over the code.  First we define a new typedef union (much like a struct) and then define one of it’s variables to be a struct itself.  We define them as uint8_t variables but they aren’t actually.  Their sum total makes up 8 bits but we define their length by using the “:  1” after their name is declared.

uint8_t PMUXEN: 1;  //This says it will make up 1 bit of a final 8 bit value
uint8_t :       3;  //This says it will make up 3 bits of a final 8 bit value

You’ll notice a few values of that internal union struct don’t have names.  That’s because those bits are reserved and cannot be changed.  By not having a name they become inaccessible but still take up the proper space.

At the end of the struct we define a name “bits” so we know those are the bits and then declare a new 8 bit variable called “reg” to access the entire register all at once if we wanted to.  Now lets put together this union stuff with our structs and turn on our LED.

#define _REG volatile  //So we don't have to write out volatile every time

typedef union {
  struct{
    uint8_t bit0: 1;
    uint8_t bit1: 1;
    uint8_t bit2: 1;
    uint8_t bit3: 1;
    uint8_t bit4: 1;
    uint8_t bit5: 1;
    uint8_t bit6: 1;
    uint8_t bit7: 1;
  } bits;
  uint8_t reg;
} STD_PORT_8;

typedef struct {
  _REG STD_PORT_8 DIR;    //1: OUTPUT, 0: INPUT
  _REG STD_PORT_8 DATA;   //1: HIGH, 0: LOW
} PORT_REG;

#define PORTB_REG ((PORT_REG *) 0x24)

int main(void) {
  //The -> is used to access a part of the struct pointer
  PORTB_REG->DIR.bits.bit5 = 1;
  PORTB_REG->DATA.bits.bit5 = 1;
}

Well that’s a ton more code for doing something we’ve already done before!  That is true but now we have a code we can use easier.  As you move on from just turning on an LED to using things like i2c, spi, uart, pwm, etc. things can get really complicated fast if you don’t organize your code properly.

Typedef

Now let’s get into why typedef is so helpful by using a function.  So let’s just go over one of my use cases for now.

void gpio_toggle(PORT_REG * port, int pin) { 
  port->OUTTGL |= PIN(pin);
}

This function takes in two variables,  our typedef struct PORT_REG and a pin.  NOTE: The PIN(pin) is just a #define that will provide the proper pin for this function, don’t worry about the details.

Here we have piece of code that will toggle the output of a GPIO.  The best part about this is it’s dynamic to any port (PortA, PortB, etc).  To use it just simply type in the following:

#define PORTA_REG ((PORT_REG *) 0x20)  
#define PORTB_REG ((PORT_REG *) 0x24) 

//Simplified to assume that the gpio_toggle function is already delcared
//and that the DIR is already an output
int main(void) {
  gpio_toggle(PORTA_REG, 3);  //Will toggle pin 3 of port a
  gpio_toggle(PORTB_REG, 7);  //Will toggle pin 7 of port b
}

Even if you forget how to toggle a pin all you have to do is know how to properly use this function (which is easy) and you’re all set.  A simple example but as things get more complex you’ll see the advantages of doing things like this.

Let’s look at another example that’s a bit more complicated:

void uart_initialize(SERCOM comm, SERCOM_REG uart) { 
 SERCOM_REG * reg; 
 reg = (SERCOMBASE_OFFSET + (0x0400 * comm)); 
 *reg = uart;
}

This function takes in two variables, the one we care about is SERCOM_REG.  Because I made it a typedef I can use it like any other variable and pass it into this function easily.  This allows me to set up UART parameters first then pass it to the proper UART register without having to look up every comm port address.  Plus it lets me put error detection in it.

void uart_initialize(SERCOM comm, SERCOM_REG uart) { 
 if(comm > 5) { 
   return;  //ERROR COMM CANNOT BE LARGER THAN 5!!
 } 
 SERCOM_REG * reg; 
 reg = (SERCOMBASE_OFFSET + (0x0400 * comm)); 
 *reg = uart;
}

Again not complex examples but they do provide you some insight on how they can be used.

Wrap Up

That was a long post…. Hopefully you got an understanding of what your previous code was doing and how we’ve improved upon it.  While it may seem like we went from a pretty straight forward coding solution in the last section to a more convoluted one, remember that doing things the quick way can lead to headaches down the line.  That said also keep in mind that just because you can use a car to drive from your house to your neighbors doesn’t mean you should.  Why go through the effort of finding the keys, starting the car, finding parking, maybe having to move it later, etc. when you can just walk?

This was more of an example of how you can access register and set things up better but it’s not the best for everything you code.

Get a feel for your project and code to a format you think makes sense.  Sometimes doing the simple solution is the way to go.  Like I said before, at the end of the day there are a lot of different ways to get to the same solution.  While it’s great that my code is easier to understand, and build upon, if it’s only job will always be to power on an LED.  Is it worth typing out 30 lines of code when 4 will do just fine?

Where that becomes a problem is when a project starts with just turning on the LED, but soon they want to toggle it.  Then they want to control it via UART, and have a status of whether it’s on or off.  Maybe they say they want an interrupt that toggles it if it’s been on for too long.  Projects tend to get more complex not simpler, so a bit of planning and foresight goes a long way.

I keep saying the next section will be Assembly but this time I mean it.  It’ll be an overview of what Assembly is and how to use it for debugging.  The section after that will likely be organizing your code into separate files for reuse and to keep it all nice and neat.

Thanks for reading and I’ll see you next time.

-Ozzie

Moving Beyond Arduino Part 2

Now that you see some of the advantages of using a development platform I’ll show some basic example code using the ATMEGA328PB Xplained-Mini dev board.  First, I’ll go over reading the datasheet and extracting the information that matters to you.  This is a key skill to have when starting out.

This tutorial is a lot longer than anticipated but maybe 10% is actually going over the code itself.  So don’t think that coding your board is going to be a painful process.  At the end the code we only end up writing 4 lines of code.  That’s it!

So don’t be intimidated by what you see, I’ll go through step by step.  Of course you don’t have to use the Atmega board and if you’re using another MCU, such as TI, the code I write won’t work exactly for your board but the fundamentals are the same and at the end of the day it’s still C coding.  So once you learn certain coding techniques then you can bring them into any MCU.

First things first, download whatever IDE your MCU uses.  I’ll provide a link for the Atmel Studio IDE which I’m using.  I won’t go over installation just follow the instructions it should be a painless process.

http://www.atmel.com/microsite/atmel-studio/compiler-editor.aspx

While that’s downloading figure out what chip you’re using on your dev-board and download the datasheet for it.  It should be a large pdf (typically a couple hundred pages) that goes over every detail you need to know about a chip… mostly.

After you’re all set with your IDE we can start coding.  Typically you can go to File-New and select Project.  There should be options for what board/chip you’re using, in my case it’s atmega328pb which I select and named the project Tutorial_Part2.  You can name your project whatever you want.  NOTE: If you already know your way around an IDE you can skip datasheet/coding part below.

IDE

Every IDE is set up a little differently but typically there will be a project navigator, an output/error window and a bunch of other stuff you might need.  For now let’s just go over the project navigator.  The other windows will be used a bit later.  No matter what, focus on what you need to use and not everything they provide you, otherwise you’ll get overwhelmed.  Just focus on what I’m describing for now.

Quick Definition: Function – I use this term a lot and you’ve already had experience with this in the Arduino IDE with things like setup() and loop().  Those are functions which just house code and can be called by just using typing the words loop() into your code.  You probably made functions yourself in Arduino to help keep you code neat.

Rather than describe something that’s been already talked to death in other forums/blogs.  I’ll post a link to the Arduino tutorial on functions.

https://www.arduino.cc/en/Reference/FunctionDeclaration

Back to the IDE.

The project navigator just shows the files associated in your project and there folders.  If you’re not using an example code it should be pretty bare.  This is where you can addAtmelStudio_PN folders to separate different libraries you write (or copy) to keep things nice and neat.  The files you care about now, are files that have the extension “.c” or “.h”.  The “.h” is for a header file which defines constants, functions, etc. that can be used by it’s “.c” counter part.

For example, I can have a “led.h” that defines the pins that the LED are on and the names of functions that will be declared in “led.c”.  So I declare that the function’s name will be “led_on()” but don’t write any code to define what it does in my “led.h” file.  Then I create my “led.c” file and fill in the detail there.  This is a standard C coding format for creating separate files that house code.

A quick note before moving on.  A header file doesn’t need to have “.c” file associated with it.  You can just use a header file to declare variables or define other types as well.  Don’t worry about that now but just so you don’t go thinking every header file needs a “.c” file too.

Looking at your project you’ll likely see a main.c file, which is common but not required.  They can be named something else but it still has to house the “main(void)” function.  You can think of the main.c file as the main program code.  This is what it’ll program into your chip.

You can write a million lines of code in other files you make and it won’t do anything unless it’s referenced inside this main.c file.  If that doesn’t make sense it will by the next lecture or two.

Coding/Datasheet

Now for some coding. (finally)  Don’t worry we’ll go over the other windows as they come up.

For now delete all of the code inside the main(void) function and everything before it so all you have is this:

int main(void){ 

}

Now lets turn on an LED… but how?  You need to read the datasheet, and before you go “Well that was fun but I’m not reading 700 pages of a datasheet just to turn on an LED” you don’t have to read the entire thing.  It’s split up into sections each a few pages long that go over every segment on how the chips works.

If you’re interested, it always good to read the pages that describe the chips architecture just to know for your own knowledge.  A good datasheet will have all of the information you need to do each task in it’s own section and if it’s not there, it should reference previous sections so you know what to read.

For the Atmega328pb the section that we care about is 17 (I/O port) other datasheets might say GPIO instead but it’s the same thing in this case.

I recommend you read it, get an understanding of how to configure the output and comeAS_IO_DS back to go over coding it.  Just be aware that a lot of that section goes over register descriptions, which you need to know but can be a bit confusing so when you get to that part feel free to return here.  Or you can just not listen to me and skip reading the datasheet and move forward with the tutorial, hey it’s your life.

Ready?  Ok let’s move on.

For this simplified 8-bit MCU, all we have to do to turn on the LED is configure the pin to be an output, something you should be used to, and set the output high.  Nothing crazy here, but the hard part (at least starting out) is how?

How do I tell the CPU to do these things?  Well look at your datasheet and go to the register description.  What are registers?  They are places in memory that can either just hold generic values for your personal use or specific ones that have very specific uses.  In this case these places in memory tell each pin what it’s “job” is (to be an input or output) and what value it should be.

How do we write to them?  Simple, at least in C code, we “point” to the memory address and write to it.  We just need to know what it’s address is, which is stated in the datasheet, and use that.  Easy!

Our LED is on Port B pin 5 (that info should be in the schematic provided by Atmel).  So we look for Port B and see the Direction register’s offset is 0x24.  If you don’t know HEX then google it, it’s easy and I can’t explain everything!  In our case that’s just the address but in other MCUs the offset might have a base address.  So the base address might be 0x10 but then we have an offset of 0x08, so the address for the register is really 0x18 (0x10 + 0x08, simple enough).

Now the register’s size is 8 bits (surprise, surprise), what do all those bits represent?  The datasheet tells you right there.  In this case each bit represents a pin.  So in order to set Pin 5’s direction we change the 5th’s bit value in the register.  Here a ‘1’ represents an output.

AS_IO_REg.PNG

So, just to recap this info, some places in memory have specific uses and each bit in that memory location has a use.  In our case we care about memory location 0x24 and the 5th bit.  NOTE: Be aware when I say the 5th bit it’s using bit 0 as a starting part.  So really it’s the 6th location if you started counting from 1 but that’s not how binary is used.  We always start from 0.  This is the same everywhere including Arduino so this shouldn’t be new to you, hopefully.

Coding For Real

Now let’s code, no seriously this time.

Let’s write a piece of code that access this point in memory first we start with this, which we put before the main(void) function.

#define LED_DIR        ((uint8_t *) 0x24)

….What is that?  Think of a #define as a variable (like int a = 5) it’s not exactly like that but for now just use that as a reference.  I’ll go into details later.  Don’t even worry about the * for now, let’s just say it’s used to access memory.  The uint8_t is easy.  It’s like a integer (AKA int) but defines that it’s unsigned (don’t worry about it for now) and it’s 8-bits long.  That last bit is what really matters.

Everything we’re dealing with at the moment is 8-bits but things like integers can vary in length.  Sometimes they’re 16 bits or 32 bits.  Our memory address are 8bits wide and it’s good practice to use the right bit size.  Yes you could use “char” too but I prefer this method which clearly defines how long the data type is.  There is uint8_t, uint16_t and uint32_t.

This LED_DIR that we just defined, is going to be used to access that register we read about.

Inside the “main(void)” function type the following:

*LED_DIR = 0x20;

All this is doing is saying, put 0x20 into memory address 0x24.  Why 0x20?  If you know HEX this translate to the following in binary: 0010 0000.  You’ll notice a 1 in the 5th bit (remember the bit all the way on the right is the 0th bit).  Per the datasheet, putting a 1 in that location tells the MCU that pin 5 needs to be an output in Port B.

So the code should be as follows:

#define LED_DIR ((uint8_t *) 0x24)

int main(void) {
    *LED_DIR = 0x20;
}

Now lets do the same thing for the Data register.  We need to tell the output to be “1”, or high.

Take a min to look over the datasheet and figure out the data locations and what bits to change.  Write the code in the same format as the LED_DIR (use LED_DATA) and see if you get what I have.

Here’s what you should get:

#define LED_DIR       ((uint8_t *) 0x24)
#define LED_DATA   ((uint8_t *) 0x25)

int main(void) {
   *LED_DIR = 0x20;
   *LED_DATA = 0x20;
}

Pretty easy right?  Might not be clear how exactly the code is doing what we want but for now that doesn’t matter.

Another Day, Another Error

Now compile the code.  In Atmel Studio it’s under Build-Build Solution or just use F7.  And you get …. an error in the error window.  This is pretty common, not this error necessarily but making a simple mistake that causes a failure like this.

Most of the time it’ll be a syntax error like missing a ; or something like that.  In this case it has no idea what uint8_t is.  The error window will point them out to you and provide a location, if there is one.  If there is you can double click it go to the problem source.

If you used libraries in Arduino before then you know you need to include them.  Here it’s no different but how do you know what library defines the uint8_t variable?AS_Error.PNG

Easy, simply right-click it and hit Goto Declaration (Alt-G in Atmel Studio).  Every single IDE has this, it might not be exactly the same (it might be Declaration with a sub menu) but no mater what you can find where it started from.  Then simply look at the name of the file (near the top) and simply “include” it at the top of your code (outside the main(void)) like so:

#include "stdint-gcc.h"

Depending on your IDE it’ll be different but you get the idea.  This is huge though.  If you’re having trouble figuring out how to do something.  Taking standard example code from the chip manufacturer and using this method to backtrack, is vital to saving yourself a headache.  I’ve hit road blocks where I was misreading the datasheet. looked at the example code and this simple method helped me figure out where I was going wrong.

Now compile and you should see no errors.

This might seem like a lot compared to Arduino but consider this.  You just learned how to program an MCU the way every other engineer does.  They go through the datasheet figure out how to access the write registers, write to them and go.  Plus the code you wrote is actually really simple (just 4 lines) and you have everything you need to turn on an LED.

Plus this code can be used anywhere else too.  It’s not Atmel dependent (minus the memory locations), that is another big advantages of this.  As you learn more coding tricks you can bring them anywhere.

The hardest part was going through so you understand, on a basic level, how to look at a datasheet and figure out everything you need to know.

Programming the MCU

Now lets code it into our MCU.  Getting to them to work on the IDE should be easy but there might be a little set up that can be annoying.  Read your dev-boards user guide or starter guide (if they aren’t the same thing).  That should go over how to setup your board if there is any weird things you have to do.

For the Atmega board there is some setup up.  After you plug it into your computer and it installs the right driver (should be automatic) then go to Project and Properties.

Go to the Tool tab and you should see the following:

328PB_Error_Fix

Change the debugger/programmer to what you see below or your equivalent:

328PB_Error_Fix_Detail

You should be good to go.  If you see this error:

328PB_Error

Hit yes and it should go away.

Now hit the Debugging button, the top green arrow that is completely filled in (or just F5).  There is another green arrow that’s hollow, don’t hit that one.

If all goes well you should have a nice orange LED.  If you’re still having problems let me know, provide some details and I’ll see if I can help fix the problem.

Debugging

Now lets look at the memory, which is great when you’re debugging a problem with your code.  Hit the stop button on the top to stop debugging and then hit the Step-Into button near the green arrow up top (or just F11).  This goes through your code one line at a time.

It should have started to debug again but now you get this arrow in your code.

AS_Arrow.PNG

When you see this (plus the green arrow is no longer grey’d out) then you know the MCU has paused at that part of the code.  Here’s where the magic happens.  Here you can look memory which should be below where the error window was.

AS_Mem

You can see a lot going on here.  Let’s tackle it one part at a time, notice there are three major columns here.  On the left column is the HEX value for the memory address and it’s values are in the center.  To be clear all of those values in the center are not for the value on the left.  The left most value (which is two numbers/letters) is associated with the value on the left column.  The rest are associated with next memory locations.  So 0x20’s value is 0x0C, 0x21’s value is 0x94, 0x22’s value is 0x64, etc.  Take a second and make sure that’s clear.

The right most column is the ASCII value for what’s in memory.  Don’t worry about that for now.

So let’s say you wanted to look at memory location 0x24.  In the address box above memory type in 0x24,data.  This will take you to the data memory area and location 0x24.  The data at that location and 0x25 should be 0x00.

Why do you need the ,data at the end?  These MCU’s have memory split between program and data, it’s called a Harvard Architecture.  So 0x24 in program memory is different than 0x24 in data memory.

Now hit F11 (or the step-into button) and the arrow up top should move the next line of code and you should see 0x24’s value change to 0x20.  Notice how it went from white to red as well.  That’s just showing you what changed in memory since the last time you paused the MCU, a really helpful tool.

If you hit F11 again it should also change 0x25’s value to 0x20 and you should see the LED come on.

This is an incredibly powerful tool; being able to go step by step through your code and watch it work in real time is amazing.  It makes debugging so much easier since you can see immediately if your code isn’t doing what you think.

Wrap Up

Just like that you’re looking at the bare metal of a MCU change right in front of you.  It’s not as low level as you can go.  We’ll go over assembly next time because this went on way longer than intended, which is really as low as you can go.

With these tools you can do w/e you want with your dev-board and access all points in memory.  It’s not the cleanest method for accessing memory but we’ll go into better coding practices after we go over more fundamentals.

The next tutorial I’ll go over looking at the assembly that is created from your C code, the registers in the CPU itself and then actually go into C coding.  Specifically what I just did in this code and maybe go into better coding practices for accessing memory.

Thanks for reading,

-Ozzie

Moving Beyond Arduino Part 1

For many people coding on the Arduino, and all of it’s variants (Mega, Zero, Micro, etc), is enough for their needs.  For others, it’s a great stepping stone but is extremely limiting and is to high level.  If you’re in school for electrical/computer engineering then, to me, you have to move past the Arduino environment but there’s nothing wrong with starting there.  If you’re a hobbyist who wants to learn more, then it can be hard to find a guide that really goes over the things you should know.

I find that a lot of guides focus on either going from the Arduino Uno/Mega to the Zero or some other type of faster version of it.  Even if you move to a new board entirely, their tutorials will focus on their own libraries.  That takes away some of the magic of really learning how the microcontroller (MCU) works.  Sure, it might be more work but you really learn what’s going on and when things work, it feels that much more satisfying.  Not to mention these libraries are usually built in a way that supports hundreds of boards and dozen of families of chips.  It can be overkill.

I plan to go over various boards you can use, what typical hardware is in them, what IDE’s there are, how to get started with them, coding techniques, different things I wish I knew out the gate and more.  If you’re wondering what IDE means (integrated development environment) it’s just a coding environment you use to compile and program your MCU.  You already have experience with the Arduino IDE seen below.

Arduino_IDE
Arduino IDE

If you’re thinking of learning more about MCU’s but you’re not sure what the advantages are of using a different IDE than the Aruidno one is, then I’ll name a few:

  1. Better debugging tools.  You can access memory and do things step by step in a way that makes finding problems so much easier.  Although it can a little confusing at first.
  2. You learn to work with raw C code and not just the Arduino version of it.  Not to say Arduino coding isn’t C-like (the libraries are actually C/C++), quite the opposite but it does simplify things in a way that isn’t done in standard MCU programming.
  3. You can access the assembly code easily and even write some if you need to.  If you’re unsure what “assembly” is then don’t worry, I’ll go over that in the next part.  Or if you do know what it is and fear you’ll have to learn assembly don’t worry, it’s a good thing to know but isn’t something you need to be great at.  Just understanding the basics is enough.
  4. Better control of the MCU, which can lead to faster programs and less overhead.  Because so much of the back-end code is hidden from you by Arduino, it’s hard to find out why your code is running slow.  Is it the library you’re using, the general way the IDE converts what you’ve written or some other unknown reason?

Of course there are other ways of coding that don’t use any IDE and just a basic text editor/command lines, but for now the focus will be using the chip designer’s IDE.

This first post is going to go over the different MCU vendors, their IDE’s and the boards you can use.  This is by no means a “these are the best boards to use” list.  I’m only going by what I’ve used but there are plenty of other options out there and I suggest you find ones that best fit your needs.  This is just to show you what’s out there.

I’m also not going through every board I’ve used by each manufacturer either, mostly for the sake of keeping this relatively short.  I’ve used probably 7 Texas Instrument (TI) dev boards alone over the last few years but only mention two.  If you have an exact application you’re looking for, I suggest you look at their websites (TI, Atmel, Microchip, ST, etc) and do a little research.

Finally, I’ll be focusing on 8-bit processors because it’s a good, easy transition from Arduino (which is also 8-bit) to the standard 8-bit MCU’s out there.  They’re typically simpler to use than 32-bit ARM processors that I will be going over at some point in the near future.

ATmega328PB Xplained Mini (link)

This is probably the most natural progression from the Arduino just because this is the same family of chips that’s used on the Arduino.  The 8bit-AVR architecture is easy to use and the datasheets that Atmel makes are top notch.  Relatively easy to read and goes in depth.

The IDE is based off of visual studio (VS) which is either a plus or a negative for you depending on your history with VS.  For me it was a negative because VS has always been slow for me for both normal use and special cases (I’m looking at you Unreal Engine 4…).  It’s gotten better over the years but it’s still not great.  Thankfully Atmel did a great job and it doesn’t feel slow or hindered at all and overall is a pretty good IDE.

I’ll be using this board in the next parts of this series since I like the AVR architecture and it’s a really cheap board (~$10).

Curiosity Development Board (link)

This is a great development board for a few reasons.  Easily swap-able chip so you can program it, remove it and tack it onto any board you make.  A ton of options for peripherals and it’s pretty cheap (~$20).  This is a Microchip made board for their PIC architecture and, having used a lot of different IDE’s, I have to say there’s is by far the most beginner friendly.

To give some context here’s Microchip’s IDE:

Microchip_IDE

And here’s Atmel’s:

Atmel_IDE

You’ll notice there are a lot more buttons up top and at first glance you’re not sure what to do… it can be a little intimidating.  But looking at Microchip’s, it seems simply and clean, just like the Arduino IDE.  This reason alone is why I recommend it to people who look at the Atmel IDE (or the TI IDE) and go “What the hell is that”?

But to be clear, using any of these is actually pretty easy.  There might be a lot more buttons but there’s really 3-5 that really matter (in the beginning) and that’s all you need to get started.

MSP-EXP430G2 LaunchPad (link)

I’ll be honest I have a soft spot for TI dev boards because it was an early MCU that I really got into.  Their launchpad series is fantastic with so many different options for things Wi-Fi, Bluetooth, high-performance (DSP), etc.  Plus their all pretty cheap!  Most can be bought for <$30 and this one I mention here is just $10.  This one also has the ability to swap chips which is always a plus, but if that isn’t a big deal for you I might also recommend the MSP-EXP430FR5994 LaunchPad which comes with an SD card slot and more pinouts.

Their IDE is eclipse based and is pretty good.  I’d say it’s about the same between the Atmel and the TI IDE each on has their own pluses and minuses, but you can’t go wrong with either one.

STM8S-DISCOVERY (link)

This is by far the one I have the least experience with.  I probably wouldn’t have put it on here but given how cheap it is (~$8), and the good things I’ve heard about it I figured I’d at the very least mention it.  I’ll leave it to you to see if it’s something you want to discover on your own…. no pun intended.

 

That’s it for now.  Hopefully you found this helpful.  I’m still trying to figure out what the next part of this tutorial will be.  I think I’ll just jump right into a programming example to show how simple it is to get started and then go over the common hardware of development boards, C coding techniques and what the hell assembly coding is and why you should care.

If you have any feedback on this post, futures ones or requests please let me know.

Thanks for reading and I’ll see you next time.

– Ozzie