1
\$\begingroup\$

I've been following a bare metal programming tutorial aimed to STM32 devices. The author uses a shelf development board, however, I have a custom board bought from a friend (image below).

Custom board

Due to this difference, I had to adapt the tutorial's code to my necessities.

My MCU is a stm32f030f4p6, and the developed code is on this link. The code should have blinked a LED connected to PA0, but it doesn't happen, actually, nothing happens.

I used stm32flash with the following command to flash my microcontroller

.\stm32flash.exe -b 230400 -w [file.elf] -v -g 0x0 COM14

My board doesn't have debug support, and I already checked the code dozens of time. I thought that it could be a deffect on my mcu, but when I send:

stm32flash COM14

I receive the following answer on the terminal.

stm32flash 0.6

http://stm32flash.sourceforge.net/

Interface serial_w32: 57600 8E1
Version      : 0x31
Option 1     : 0x00
Option 2     : 0x00
Device ID    : 0x0444 (STM32F03xx4/6)
- RAM        : Up to 4KiB  (2048b reserved by bootloader)
- Flash      : Up to 32KiB (size first sector: 4x1024)
- Option RAM : 16b
- System RAM : 3KiB

It seems that the communication with the board doesn't have any trouble.

Does anyone see something wrong with the code, or a specific step that I described?

Could it be a problem with my microcontroller?

Update

Some comments suggested me to create a project in STM32 Cube IDE, and use the HAL technique to turn the led on.

I tried, nonetheless, the result was the same, the led didn't turn on.

The code is shown below,

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

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

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
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();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

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

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
      HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

Update 2

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

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

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
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();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

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

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
      HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);

  /*Configure GPIO pin : PA0 */
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
\$\endgroup\$
24
  • 2
    \$\begingroup\$ Make sure your LED isn't blinking faster than your eye can see. \$\endgroup\$
    – DKNguyen
    Commented Jun 22, 2021 at 2:58
  • 1
    \$\begingroup\$ Personally, I would just use the Cube program. It is still bare metal if you use the cube. But it takes care of a lot of configuration reliably. It can generate no IDE projects relying on Makefile and gcc for arm. st.com/en/development-tools/stm32cubemx.html \$\endgroup\$
    – user57037
    Commented Jun 22, 2021 at 4:37
  • 3
    \$\begingroup\$ There are too many unrelated things that can be wrong. Please first try blinking a LED with CubeIDE generated code to know what works and what does not. Then fix your code to do the same thing without the HAL when you have a working HAL example. \$\endgroup\$
    – Justme
    Commented Jun 22, 2021 at 8:37
  • 2
    \$\begingroup\$ I just saw the update. You should try generating code with STM32CubeMX, not STM32CubeIDE. Your code above is missing GPIO intializations (GPIO pin speed, output mode, push/pull, etc.). You could also update what you have right now with a custom GPIO Initialization. \$\endgroup\$
    – Cimory
    Commented Jun 23, 2021 at 2:47
  • 1
    \$\begingroup\$ Thanks for all the supports so far. After several comments, I will get a flasher that is capable to debug, in a week or two, after I receive the product, I let you know what it is the problem with my project. \$\endgroup\$
    – andre.hre
    Commented Jun 24, 2021 at 18:56

3 Answers 3

6
\$\begingroup\$

You made this way worse by trying to use the HAL.

You didnt need to mess with RCC CR. Nor optyper, ospeedr, nor pull up. Only moder (and the clock enable).

systick is not for operating systems it is just a timer in the core that you can use to do whatever. first program do the counter loop. next experiment then use systick, poll your way through, no interrupts. Then maybe try a timer in the chip.

The primary problem is that your while loop is likely optimized out so that it is basically this:

while(1)
{
    GPIOA->ODR ^= BIT0;
}

which will blink to fast to see and probably even too fast to glow.

The linker script, vectors, bootstrap, are all over complicated for what you are trying to do right now. Even later do not need that much complication, but clearly this is borrowed code and that is fine.

Can change a few lines, in particular short term make the loop count variable to volatile.

#include "stm32f030x6.h"

#define BIT0 0x01
#define BIT1 0x10

int main(void)
{
    volatile int val;

    //enabling clock in port A
    RCC->AHBENR |= RCC_AHBENR_GPIOAEN;

    //setting GPIOA0 in output mode
    GPIOA->MODER |= BIT0;

    val = 0;
    while(1)
    {
        if(val == 1000000)
        {
            GPIOA->ODR ^= BIT0;
            val=0;
        }
        val++;
    }

}

You probably already know to press and hold boot0 then press and release reset then release boot0, before using the uart to program the device.

If you get an ftdi breakout board with mpsee (Adafruit has one for like $15) or even cheaper just get a nucleo board with a debug end (one of the wider ones) for about $10 and use that, then you can run openocd and stop and start and do debugging things like that if you feel the need. (Look at the datasheet for swdio and swclk probably PA13 and 14).

When doing a project like this disassemble a lot up front. You need to check the vector table see if it is right and would have seen if the loop had been optimized.

BSRR is easier to use than ODR in general, not necessarily for your example.

while(1)
{
   volatile unsigned int x;
   GPIOA->BSRR = (1<<(0+ 0));
   for(x=0;x<1000000;x++) continue;
   GPIOA->BSRR = (1<<(0+16));
   for(x=0;x<1000000;x++) continue;
}

with gcc ints have been 32 bits for arm from day one and continue to be, no issue there.

Nothing wrong with using a breakout board like this. I have nucleo boards, but make a bunch of these breakout boards, get to try many more mcus that way, bang out a trivial breakout in an evening, two weeks later oshpark mails the board, few (fives of) minutes of soldering. hook up the uart or a swd board or both and have fun, repeat as desired.

\$\endgroup\$
2
  • \$\begingroup\$ jlcpcb is also very cheap and maybe faster than oshpark. \$\endgroup\$
    – user57037
    Commented Jun 23, 2021 at 5:16
  • 1
    \$\begingroup\$ For the OP, HAL functions that have timeouts rely on systick. They have the potential to hang forever if systick is not running. And HAL_Delay() will not work (it will hang forever). \$\endgroup\$
    – user57037
    Commented Jun 23, 2021 at 5:18
2
\$\begingroup\$

I did it.

stm32flash application wasn't properly being used.

I changed the flashing process to stm32programmer application, the led blinked without any problem.

I saw that stm32programmer has a feature to read the memory of the uC, then I tried it again with stm32flash and I read the flash memory, well, it was practically all addresses content set to 0.

The command I was using when I posted the question is shown below:

stm32flash [code.elf] -v -g 0x0 COM14

Then I tried to replace the elf code to the bin file generated by the compile process. It worked, so the right command is:

stm32flash [code.bin] -v -g 0x0 COM14
\$\endgroup\$
1
  • \$\begingroup\$ Thank you for following up! It is always better when things get resolved. \$\endgroup\$
    – user57037
    Commented Jun 28, 2021 at 4:03
1
\$\begingroup\$

I set up the CubeMX to generate code using the low level drivers as opposed to HAL. I am using a different processor. Here is what it came up with for GPIO configuration. You have to call this function once before you try to toggle the LED. I just did this earlier today for other reasons. I am copying and pasting it here in case it helps you. I didn't actually generate the code specifically for you otherwise I would have used your processor in CubeMX.

#include "stm32l0xx_ll_gpio.h" /* May be different for your processor... */    
static void MX_GPIO_Init(void)

{
  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA);
 
  /**/
  LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_0);

  /**/
  GPIO_InitStruct.Pin = LL_GPIO_PIN_0;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

If you use the LL drivers there are three functions for IO's. One to set, one to reset, and one to toggle.

LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_0);
LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_0);
LL_GPIO_TogglePin(GPIOA, LL_GPIO_PIN_0);
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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