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;
    }
}

 

13 REPLIES 13
waclawek.jan
Super User

To me this looks like problematic power supply/PCB layout/ground arrangement.

 

What hardware is this, your own, or a "known good" board such as Nucleo?

JW

This is a NUCLEO-F401RE

Full disclosure: everything is connected via breadboard and could be suspect.

Thank you! This seems like the correct solution. 

Just to follow up this worked perfectly. I set up a 5us delay following each bit swap and the signal is now nice and clean and the DRO reads the signal perfectly.