Driving a stepper with bitwise manipulation of the PORT

In a previous article I described driving a steppermotor with an arduino. I like to use that as an example for writing directly to the ATMega328’s registers to drive the stepper.
Normally you would first set the chosen Digital pins on the Arduino to Output with pinMode and then you would set the Value of the pins with DigitalWrite. If you are using four pins to drive your stepper, this would require 4 DigitalWrite cycli per step.

“digitalWrite” is not the most efficient or fastest way to write to a port as it takes many cycli. Also, the pins are written to sequentially instead of at the same time.
That is not really a big problem for steppers as those are not time critical. It is possible however to write to all 4 pins at the same time.

If you use digital pins 8-11 to drive the motor, you are using the port ‘B’ (pins 8-13). That port can be manipulated by 3 registers and the arduino website describes those.  We need to set two registers, the DDRB and the PORTB register.

The DDRB register determines which pins will become output and if we use pins 8-11, the statement:
would set pins 8-11 to output.

There is a problem however because we also write to the higher pins –12 and 13-  and actualy to some more places that might already have a certain value that we are now altyering. It is therefore better to state:
DDRB= DDRB | B00001111;
This ‘logical OR’ function, does not change the upper four bits that might have been set to 1, it just sets the four lower bits to HIGH.
This basically takes care of the 4 pinMode statements.

The four ‘digitalWrite’ statements are taken care of by the PORTB register, but then we run into a bit of a problem: if for our first step we need only the first and the fourth bit to be HIGH and the 2nd and 3rd bit to be LOW, we cannot just write:
Yes, it will set the required pins high and low, but like with the DDRB register, we may have previously set the upper 4 bits of the register and those are now set to ‘0’ again.

We can also not use the: 
PORTB=PORTB | B00001001; because  this will leave any pins in the lower 4 bits (D8-D11)  that were previously set to HIGH untouched and they remain HIGH.

So we need a function that leaves the upper 4 bits untouched, but sets the lower 4 pins to the exact value we want.
That is done with a mask:

This mask has the pins that we want to change set to HIGH and the pins that need to remain as they are set to LOW. That allows us to write to the exact pins we want in the register with the following statement:
PORTB = (PORTB &~mask) | (B00001001); 
(actually:   PORTB = (PORTB &~mask) | (B00001001 & mask);//gives the same result )
so, the entire program will look like this:

// uses two coils and thus has extra torque
//pins D8-11 are used for the motor control

int delayTime = 100;
int mask=B00001111;// sets only the last four bits
void setup() {
 DDRB = DDRB | B00001111; //set D8-D11 to output                        
void loop() {
 PORTB = (PORTB &~mask) | (B00001001); 
 PORTB = (PORTB &~mask) |  (B00000101);
 PORTB = (PORTB &~mask) | (B00000110);
 PORTB =  (PORTB &~mask) | (B00001010);
%d bloggers like this: