328P PORT MANIPULATION

#122 ATMEGA 328P Port Manipulation

Port manipulation was not important to me when I started working with microcontrollers, in fact I didn’t even know it existed and never felt the need for it especially after programming mostly in java script and PHP using functions like digitalread(pin); or digitalwrite(pin); etc. was second nature and speed or efficiency considerations were not really necessary or thought about that much.

Then after intermittently playing around with embedded ICs I got serious during the corruption virus of 2019 during lockdowns and other dilemmas while a lot of corrupt and diabolical cronies enriched themselves. I had a lot of time to focus on a few different things. There was no way I was going to let the circumstances get to me I made sure I was achieving at least one big goal each year and not get bogged down.

I took a look at the IC market and even though there was a chip shortage there were some IC’s available. This mad me try and get into efficient code and cost per IC. I came to the conclusion that I could get hold of IC’s with low memory + flash and very affordable prices. However in order to use them I would have to learn to use port manipulation, macros and interrupts in very efficient ways to the best of my ability at the time.

Now I needed to find new and comprehensive writeups of the principal and so I found the SpenceKonde
megaTinyCore
for the new at the time tinyAVR 0/1/2-series IC’s. The core has a lot explained over the years and was very helpful and easy enough to understand but took a bit of time and real world practical implementations which made learning way more fun and easy. I always need to do practical with theory when it comes to learning I find it very hard to picture learning anything without using it practically.

Now this is about port manipulation on the 328P and I’ll get into the actual implementation now without further ado.

The ATMEGA 328P has 3 ports namely B, C, D with B (digital pin 8 to 13), C (Analog input pins) and D (digital pins 0 to 7).

For the basics you only need to understand 3 types of registers you will be manipulating.

For example:

Port B
PORTBMaps to Arduino digital pins 0 to 7 Data Register – read/write
DDRBThe Port B Data Direction Register – read/write
PINBThe Port B Input Pins Register – read only

Port C
PORTCMaps to Arduino digital pins 8 to 7 Data Register – read/write
DDRC The Port C Data Direction Register – read/write
PINCThe Port C Input Pins Register – read only

Port D
PORTDMaps to Arduino digital pins 14 to 19 Data Register – read/write
DDRDThe Port D Data Direction Register – read/write
PINDThe Port D Input Pins Register – read only

So an example using DDRD (Data Direction Register) to set input and output pins:

Another example is to set digital pins 7,5,3 high:

Now you can do port manipulation with a bit shift instead of binary or hex. this makes things a bit more readable… excuse the pun. 🙂

For example to set the input or output of a single pin you could use:

Example using hexadecimal:

Now to initiate a pullup on a single pin you could use:

Example using hexadecimal:

Example using binary:

Looking at how to read a pin you can use the Input Pins Register PINB:

it is also possible to toggle a pin and there’s different ways. Some are faster then others:

You can also easily write to a pin low or high:

There’s also an atomic operation to writing low or high:

So now that we understand the basics we can get into making life easy by creating macros

Below are 4 functions made easy to iterate over all the pins in each port B, C, D

set_PIN_HIGH(pin);
set_PIN_LOW(pin);
read_PIN_STATE(pin);
toggle_PIN_STATE(pin);

This makes it easy to call the function without having to define the port each time and it’s still fast.

See the example below:

Links:

Leave a Reply

Your email address will not be published. Required fields are marked *