1
\$\begingroup\$

I have written and using a STM32F030F4 for toggle a pin. I configured all things and my program is this (I use GPIOA->ODR ^= GPIO_PIN_2 for toggle GPIOA2 in Infinite loop ):

#include "stm32f0xx_hal.h"

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);

int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration----------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* System interrupt init*/
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);

  /* Initialize all configured peripherals */
  MX_GPIO_Init();

  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* USER CODE BEGIN 3 */
  /* Infinite loop */
  while (1)
  {
        GPIOA->ODR ^= GPIO_PIN_2; //toggle GPIOA2
  }
  /* USER CODE END 3 */

}

/** System Clock Configuration
*/
void SystemClock_Config(void)
{

  RCC_ClkInitTypeDef RCC_ClkInitStruct;
  RCC_OscInitTypeDef RCC_OscInitStruct;

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL6;
  RCC_OscInitStruct.PLL.PREDIV = RCC_PREDIV_DIV1;
  HAL_RCC_OscConfig(&RCC_OscInitStruct);

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1);

  __SYSCFG_CLK_ENABLE();

}

/** Configure pins as 
        * Analog 
        * Input 
        * Output
        * EVENT_OUT
        * EXTI
*/
void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct;

  /* GPIO Ports Clock Enable */
  __GPIOF_CLK_ENABLE();
  __GPIOA_CLK_ENABLE();

  /*Configure GPIO pin : PA2 */
  GPIO_InitStruct.Pin = GPIO_PIN_2;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

}

As reference manual has said:

figure1

Thus if 2*2=4 that mean each 4 cycle make a toggle in GPIOA2. then frequency ought to be 48/4=12MHz (48 is MCU clock because as you can see in codes I have used PLL and I have multiplied 8MHz to 6). is it correct?

let to impelement the code on MCU. look at my saleae result:

enter image description here

Huh!!!?? is the output frequency correct? is there any point?

Edit:

The assembly for the toggle is this:

figure 3

\$\endgroup\$
7
  • 3
    \$\begingroup\$ You should really look at the disassembly of your main loop. Since there is a structure involved, I almost automatically suspect it. \$\endgroup\$ – Matt Young Jul 21 '14 at 12:45
  • \$\begingroup\$ Matt has it. What is written in the datasheet is true, but you need to feed the microcontroller the appropriate instructions. \$\endgroup\$ – Vladimir Cravero Jul 21 '14 at 12:59
  • \$\begingroup\$ @MattYoung Ok, Now, I'm searching to find the assembly file that the keil made. but still I have couldn't find it. \$\endgroup\$ – Roh Jul 21 '14 at 13:05
  • 1
    \$\begingroup\$ In this case, the toggling worked fine. However, note that for some architectures, the toggling command would work by reading the pin value instead of the register value. If the pin was connected to some circuit that would cause a voltage drop, then the value read before inversion could be wrong. There is an example of a user trying to do the same while using an amp meter and by doing so, the voltage of the pin was always read as 0 so the output was always set to 1. Unless you really know what is going on (use ASM), it is better to toggle an internal register and then pass it to the output. \$\endgroup\$ – Evan Jul 21 '14 at 14:19
  • 1
    \$\begingroup\$ For one, toggle on a timer interrupt and make sure you get what you expect. \$\endgroup\$ – Scott Seidman Jul 22 '14 at 4:24
2
\$\begingroup\$

This is a bit of a generic answer rather than anything specific to that particular chip to help you understand some of the issues. When you have a piece of code like this:

while (1)
{
    GPIOA->ODR ^= GPIO_PIN_2; //toggle GPIOA2
}

It won't be a single instruction / cycle in assembler, a branch will be used to keep repeating the same instruction sequence and they'll also be an instruction to perform the exclusive-OR operation. As Matt Young suggested in a comment the only way to know the assembler output for sure is to look at the output from the compiler to see how many machine instructions are actually being used.

Another likely issue is the FLASH_LATENCY_1 which is inserting a delay while reading the FLASH that's probably not necessary at that fairly low speed. I think if you replace that with FLASH_LATENCY_0 you should see a speed improvement (depending on any caching) but it's worth double-checking the datasheet so see at what speed it's required. Many ARM cores can operate at speeds above what code can be fetched from FLASH which is the reason for that feature.

I've never used the Keil compiler so I'm not sure how to get the assembler output but often it's described as a listing file. Just searching Listing (MDK-ARM) looks like it may cover it.

Now you've found how to view the assembler output you can see there's a total of four instructions involved, the instructions between addresses 0x80009C8 and 0x80009CE are that part of the code and the last instruction is the branch that goes back to the start.

\$\endgroup\$
2
  • \$\begingroup\$ Peter, in your opinion, Is the output clock acceptable? becouse seems that's too much low \$\endgroup\$ – Roh Jul 21 '14 at 13:49
  • 1
    \$\begingroup\$ @Roh, I think the speed you're getting would match the clock setting pretty roughly. You could either try running at its full speed of 48 MHz for something faster or use a timer output that would take code timing out of the equation. \$\endgroup\$ – PeterJ Jul 21 '14 at 14:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.