cancel
Showing results for 
Search instead for 
Did you mean: 

GPIO output speed

LANLocked
Associate II

New programmer and new to the STM32 ecosystem as well.

I am working with a STM32F401 as it has 5v tolerant inputs and 2 32bit clocks.

I have a simple program that reads the 2 32bit TIMs (2&5) in encoder mode, sums the results and then outputs a quadrature signal to a device. I have the GPIO outputs set to "low" speed, which according to my reading should give them a max of 2Mhz output.

Even this appears to be too fast with the HCLK set to the maximum of 84Mhz. On a scope the signal looks pretty bad and my device (cheap DRO) cannot read the signal at that speed. 

If I drop the HCLK down to 4Mhz everything works as expected and I get real nice square waves on the scope but this feels "kludgy"

My question is, is there something else I should be looking at to adjust the output rate? HAL_Delay etc feel even more kludgy than stepping the clock down.

Any help would be greatly appreciated; Code follows

  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	    int32_t cnt1 = __HAL_TIM_GET_COUNTER(&htim2);
	    int32_t cnt2 = __HAL_TIM_GET_COUNTER(&htim5);
	    int32_t diff = (cnt1 + cnt2) - lastcnt;
	    lastcnt = (cnt1 + cnt2);

	    // Debug
/*	    float total = ((float)lastcnt * 5);
	    total = (total/25400);
	    sprintf(MSG, "EncA: %ld\tEncB: %ld\tLastcnt: %ld\tMoved(in.): %f\n\r", cnt1, cnt2, lastcnt, total);
	    HAL_UART_Transmit(&huart1, (const uint8_t *)MSG, strlen(MSG), 100);
*/
	    if (diff < 0) {
	        dir = false;
	        diff = abs(diff);
	    } else {
	        dir = true;
	    }

	    for ( int32_t cnt = 0; cnt < diff; cnt++ ){
	      if (dir == true){
	          if (current == 3) { next = 0; } else { next = (current + 1); };
	      } else {
	          if (current == 0) { next = 3; } else { next = (current - 1); };
	      }
	      quadout (next, dir);
	      current = next;
	    }

  	  } 

  /* USER CODE END 3 */
}

<SNIP>
void quadout(int next, int dir){
    //NOTE GPIO_PIN_RESET = HIGH, GPIO_PIN_SET = LOW !!
    switch (next) {
        case 0:
            if (dir == true) {
                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);
            } else {
                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9 ,GPIO_PIN_RESET);
            }
            break;
        case 1:
            if (dir == true) {
                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_SET);
            } else {
                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8 ,GPIO_PIN_RESET);
            }
            break;
        case 2:
            if (dir == true) {
                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);
            } else {
                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9 ,GPIO_PIN_SET);
            }
            break;
        case 3:
            if (dir == true) {
                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_RESET);
            } else {
                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8 ,GPIO_PIN_SET);
            }
            break;
        default:
            break;
    }
}

 

1 ACCEPTED SOLUTION

Accepted Solutions

The DRO should have a maximum "velocity" it supports. Likely it's not set up for an edge ever microsecond.

Put a small delay in the main loop after the signal is changed. Use a timer at max frequency and ensure the delay is at least X us long. That will ensure the edges are stable for at least X us.

If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

13 REPLIES 13
TDK
Super User

> On a scope the signal looks pretty bad and my device (cheap DRO) cannot read the signal at that speed. 

What does it look like on the scope?

Why is the STM32 involved at all? If the DRO needs an encoder input, just feed the signal directly.

Encoders will not output nice square waves in general. The signal will stop and start as position changes.

How fast (how many edges per second) are the signals you're outputting?

If you feel a post has answered your question, please click "Accept as Solution".
waclawek.jan
Super User

What kind of encoders are the inputs and how are they connected?

Is the signal from them "nice" on your DSO?

   //NOTE GPIO_PIN_RESET = HIGH, GPIO_PIN_SET = LOW !!

Explain.

JW

Thanks for the reply. I am using inexpensive (Sino) linear scales as inputs. I get nice crisp square waves on the input while moving either scale. 

With HCLK set to max (84Mhz) the output is very jagged with slopes on the rise and fall and more of a peak than a flat line at the top of the wave. It looks more like a noisy sawtooth wave. I don't recall how fast the signals are when seeing this.

With the HCLK set at 4Mhz I get the expected vertical rise and fall and a nice square wave. When I see this the output the time between rise and fall is in the 10-20 microsecond range which anecdotally "feels" right when observing the DRO - no lag and no missed steps.

I am at work now but can upload images tonight.

The inputs are inexpensive linear glass scales (Sino). There are only 4 pins used, Vcc, gnd, A, B.

The signal from these scales is very nice with vertical edges and nice flat peaks.

The comment is just a reminder for myself that in my configuration GPIO_PIN_RESET sets the pin high and GPIO_PIN_SET sets the pin low. 

I will post scope images tonight.

waclawek.jan
Super User

> The comment is just a reminder for myself that in my configuration GPIO_PIN_RESET sets the pin high and GPIO_PIN_SET sets the pin low.

That's not how the STM32 pins work. Do you have some external circuitry connected to them?

JW

That's not how the STM32 pins work. Do you have some external circuitry connected to them?

I have no external circuitry however I did read that this was correct somewhere. That explains why my output direction is always inverted /hangs head in shame/

LANLocked
Associate II

Reading from the scale (5v):

tDS1Z_QuickPrint1.png

Output with HCLK at 4Mhz. DRO reads this fine:

DS1Z_QuickPrint2.png

Output with HCLK at 84Mhz. This is much cleaner than what I previously could get however the DRO still cannot read this:

DS1Z_QuickPrint3.png

My working theory is that the frequency of the last output is too high for the DRO to read. How can I rate limit this output to ~20Khz or so without setting HCLK to a lower value? Or is setting HCLK to a very low value an accepted solution?

LANLocked
Associate II

DS1Z_QuickPrint5.png

 I should also mention that despite moving the scale at a steady rate, the output seems to be grouped in small blasts of signal.

The DRO should have a maximum "velocity" it supports. Likely it's not set up for an edge ever microsecond.

Put a small delay in the main loop after the signal is changed. Use a timer at max frequency and ensure the delay is at least X us long. That will ensure the edges are stable for at least X us.

If you feel a post has answered your question, please click "Accept as Solution".