timers and direct port manipulation

I’m trying to setup timer 1 to toggle a digital pin for the pulse signal to a stepper motor driver. I’m using an Atmega1284P.

I can’t seem to get the pin to toggle. It goes high and seems to stay high. Digital pin 3, Port B pin 3

// avr-libc library includes 
#include <avr/io.h> 
#include <avr/interrupt.h> 
    
void setup() { 
  DDRB |= 0x08;
  PORTB |= 0x08;
  cli();          // disable global interrupts  
  TCCR1A = 0;     // set entire TCCR3A register to 0 
  TCCR1B = 0;     // same for TCCR3B 
  
  // enable Timer1 overflow interrupt:
  TIMSK1 |= (1 << TOIE1);
  // Set CS10 bit to start timer with no prescaler, timer will overflow every 4.1ms
  TCCR1B |= (1 << CS10);
  sei();
}
void loop() { 

}

ISR (TIMER1_OVF_vect) {
  int z = 0;
  
  PORTB &= ~0x08;
  while(z++ != 10); 
  PORTB |= 0x08;
}

I verified the wiring and hardware side is setup correctly by running this sketch and it works fine.

int dirpin = 24;
int steppin = 3;

void setup() 
{
pinMode(dirpin, OUTPUT);
pinMode(steppin, OUTPUT);
}
void loop()
{

  int i;

  digitalWrite(dirpin, LOW);     // Set the direction.
  delay(3000);


  for (i = 0; i<8000; i++)       // Iterate for 4000 microsteps.
  {
    digitalWrite(steppin, LOW);  // This LOW to HIGH change is what creates the
    digitalWrite(steppin, HIGH); // "Rising Edge" so the easydriver knows to when to step.
    delayMicroseconds(700);      // This delay time is close to top speed for this
  }                              // particular motor. Any faster the motor stalls.

  digitalWrite(dirpin, HIGH);    // Change direction.
  delay(3000);


  for (i = 0; i<8000; i++)       // Iterate for 4000 microsteps
  {
    digitalWrite(steppin, LOW);  // This LOW to HIGH change is what creates the
    digitalWrite(steppin, HIGH); // "Rising Edge" so the easydriver knows to when to step.
    delayMicroseconds(700);      // This delay time is close to top speed for this
  }                              // particular motor. Any faster the motor stalls.

}

Thanks,

 int z = 0;
  
  PORTB &= ~0x08;
  while(z++ != 10);

The compiler can see that this diddling with z accomplishes nothing. So, it removes the useless code, leaving:

ISR (TIMER1_OVF_vect) {
  PORTB &= ~0x08;
  PORTB |= 0x08;
}

Which I'm sure you can see doesn't accomplish a lot.

You can toggle an IO pin with just this:

PINB = 0b00000100; // write a 1 to input register to toggle the bit

"Three I/O memory address locations are allocated for each port, one each for the Data Register – PORTx, Data Direction Register – DDRx, and the Port Input Pins – PINx. The Port Input Pins I/O location is read only, while the Data Register and the Data Direction Register are read/write. However, writing a logic one to a bit in the PINx Register, will result in a toggle in the corresponding bit in the Data Register."

Thanks Guys, Is that not the proper way to do a while statement? I need a slight delay before toggling the pin back to its original state or the stepper driver does not detect a pulse.

Is that not the proper way to do a while statement?

The syntax is valid. But, the compiler sees that the while loop accomplishes nothing. So, it removes it. Wasting time is not something that the compiler supports. delayMicroseconds() could be used.

Why are you trying to step the motor using just a timer? How do you plan to control direction?

CrossRoads: You can toggle an IO pin with just this:

PINB = 0b00000100; // write a 1 to input register to toggle the bit

"Three I/O memory address locations are allocated for each port, one each for the Data Register – PORTx, Data Direction Register – DDRx, and the Port Input Pins – PINx. The Port Input Pins I/O location is read only, while the Data Register and the Data Direction Register are read/write. However, writing a logic one to a bit in the PINx Register, will result in a toggle in the corresponding bit in the Data Register."

Is it is recommended to OR the port pin register to avoid changing the state of pins you don't wanted changed.

PaulS:

Is that not the proper way to do a while statement?

The syntax is valid. But, the compiler sees that the while loop accomplishes nothing. So, it removes it. Wasting time is not something that the compiler supports. delayMicroseconds() could be used.

Why are you trying to step the motor using just a timer? How do you plan to control direction?

Thanks.

I’m actually working on the code for a 3 axis cnc mill. Through the serial monitor I enter in the axis I want to move followed by the position I want it to go to. I couldn’t get any of the axis to move using that code so I dumbed it down severly so I could find what the issue is. In my cnc code the timer is setup in ctc mode instead of overflow. There is an output for direction that is toggled based on the commanded position vs the actual position.

My plan is to use grbl but not until I understand what is going on behind the scenes.

Is it is recommended to OR the port pin register to avoid changing the state of pins you don't wanted changed.

No, only the 1 bit written to will toggle.

I do is this way a lot also, when I don't want to just blindly toggle the bit:

PORTD = PORTD & 0b11111011; // clear bit 2
PORTD = PORTD | 0b00000100; // set bit 2

I take it that if I need to set an input pin HIGH (enable internal pullup) I need to toggle the appropriate bit within the PORTx register???

my overtravel prox's connect to GND when active, they are NPN.

"set an input pin HIGH" and "enable internal pullup" are two different things.

PORTx is an output register. Whether a pin is an input or an output is determined by DDRx, the data direction register. The IDE does some things for us with the pinMode command - INPUT, OUTPUT, INPUT_PULLUP to enable the pullup resistor, and after using pinMode (pinName, INPUT); then digitalWrite (pinName, HIGH) will also enable the pullup resistor and digitalWrite (pinName, LOW) will disable it.

My main shortcuts are using pinMode to make a pin an output, then either PIND = 0b00000100; // to toggle a specific bit, or PORTD = PORTD & 0b11111011; // to clear a specific bit PORTD = PORTD | 0b00000100; // to set a specific bit

A summary from the datasheet: "Three I/O memory address locations are allocated for each port, one each for the Data Register – PORTx, Data Direction Register – DDRx, and the Port Input Pins – PINx. The Port Input Pins I/O location is read only, while the Data Register and the Data Direction Register are read/write. However, writing a logic one to a bit in the PINx Register, will result in a toggle in the corresponding bit in the Data Register. In addition, the Pull-up Disable – PUD bit in MCUCR disables the pull-up function for all pins in all ports when set."

You can read a lot more about these in Section 14 of the datasheet.