AnsweredAssumed Answered

Auto-running program from flash memory after reset vs attached to debugger - not working?

Question asked by gunn on Feb 26, 2011
Latest reply on Feb 27, 2011 by Clive One
A friend gave me this STM32 Value Line Discovery board for a project I'm building. I haven't programmed anything more complicated than a batch file in 10+ years so I was quite amused when I got most of the way through my project. Things have gotten a lot more complicated since my days of programming a 16bit motorola microcontroller but I seem to have made quite a bit of progress. My goal is to be able to write a program that reads a tilt sensor, decide which direction its tilting, and signal out two pins accordingly.

However, I've hit a wall and I'm hoping one of you folks might be able to answer my question:

The goal is to load the program into the FLASH memory of the STM32VL-Discovery board and then to be able to run it w/o having a PC attached. Basically, with power coming in via a USB wire, the board should "wake up" and begin running the program that was last flashed into its memory.

I can seem to do this for the example programs but I was unable to do so with the program I wrote. Through a bit of trial and error, I realized that if the program being loaded was larger than 1024 bytes (I think you see this when you enter the uVision tools debug mode with Control-F5), the program would NOT automatically start to run if the board was reset. For example, I can take the standard blinky program, compile it, and send it over the USB line to the board, the program will run automatically even if I get out of the debugger and just connect it to power (thereby resetting the board). The same is NOT true if the program is >1024 bytes.

Can someone tell me what I'm doing wrong? If one disconnects the power to the USB port and plugs it back in, why wont my program just start running like the blinky program and a more cut down version of my program (that just inits the ports and turns on the LEDs).

IDE/Debugger: Keil RealView MDK-ARM Ver 4.14
- The debugger says its an eval version and is limited to 32KB program (suits me).
So far, I managed to do the following:
- get the IDE up and running
- Compile the example programs
- Create a new project based on an example project and extract the necessary dependency files into a single folder
- modify the new project to suit my needs
- compile it and get the program working in the debugger.

Here's my program (it's nothing fancy).
Thanks in advance,

UPDATE: See below about what I tried and the solutions I found.
Step 1: determine if the program really is not running or if the input sensor was just not being read correctly. I did this by making the USER button flash BOTH the LED3 and LED4 lights.
Step 2: track down the offending piece of code. In my case, it was declaring the mode of the inputs as IPU vs. IPD. GPIO_Mode_IPU only worked when the debugger was attached while Mode_IPD works in both instances. 
I don't know why....

* @file    main.c
* @author  Gunn
* @version V3.1.0
* @date    02/26/2011
* @brief    Inputs: two switches wired to PA2 and PA3. Switch pushed == GND.
*   Outputs: circuitry for Relays (currently LEDs) plus onboard LED3 and LED4  
*   + Unbouncing
*    + Inputs / Output Pins configurable with DEFINE (Bus is still hardwired)
*   + comments removed

/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "STM32vldiscovery.h"

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define UNBOUNCE_CNT       5  // unbounce input... Number of times to check tilt sensor */
#define RELAYTIME 0xAFFFF // Set Delay time to keep Relays ON

//Input Pin Bus GPIOB
#define INPUT_PIN1 GPIO_Pin_8 // Set Pin 1 for Input Sensor
#define INPUT_PIN2 GPIO_Pin_9 // Set Pin 2 for Input Sensor

//Output Pin Bus GPIOC
#define OUTPUT_PIN1 GPIO_Pin_1 // Set Pin 1 for Output [moved since rev 3.0] 
#define OUTPUT_PIN2 GPIO_Pin_2 // Set Pin 2 for Output [moved since rev 3.0]

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
GPIO_InitTypeDef GPIO_InitStructureInput; // Structure for Input Definitions
GPIO_InitTypeDef GPIO_InitStructureOutput; // Structure for Output Definitions
uint32_t InputCheck   = 0; // Set input trigger counter to 0

/* Private function prototypes -----------------------------------------------*/
void Delay(__IO uint32_t nCount);

/* Private functions ---------------------------------------------------------*/

int main(void) {
  int BounceCheck = 0;
  /*!< At this stage the microcontroller clock setting is already configured,
       this is done through SystemInit() function which is called from startup
       file (startup_stm32f10x_xx.s) before to branch to application main.
       To reconfigure the default setting of SystemInit() function, refer to
       system_stm32f10x.c file
//  SysTick_Config(SystemCoreClock / 100);       /* Setup SysTick Timer  (10ms). Not sure why I need this so commented out */
  /* Init Inputs */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // I guess you need to enable the CLOCK before reconfiguring it
  GPIO_InitStructureInput.GPIO_Pin = GPIO_Pin_All; // Might as well set all of them to INPUTS even though I just need PA0 for USER button.
  GPIO_InitStructureInput.GPIO_Mode = GPIO_Mode_IPD; // Means Pull Down Input
  GPIO_Init(GPIOA, &GPIO_InitStructureInput); // Send Struct to GPIOA

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
  GPIO_InitStructureInput.GPIO_Pin = INPUT_PIN1 | INPUT_PIN2;
  GPIO_InitStructureInput.GPIO_Mode = GPIO_Mode_IPU; // Means Pull Up Input aka ON == GND
  GPIO_Init(GPIOB, &GPIO_InitStructureInput); // Send structure

  /* Init Outputs */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
  GPIO_InitStructureOutput.GPIO_Pin = OUTPUT_PIN1 | OUTPUT_PIN2 | LED3_PIN | LED4_PIN;
  GPIO_InitStructureOutput.GPIO_Mode = GPIO_Mode_Out_PP; // Push Pull aka Correct Mode to output LED on wire
  GPIO_InitStructureOutput.GPIO_Speed = GPIO_Speed_50MHz; // Correct Speed to output LED on output wire
  GPIO_Init(GPIOC, &GPIO_InitStructureOutput); // Send Struct
  STM32vldiscovery_LEDOff(LED3); // turn LED off to start out
  STM32vldiscovery_LEDOff(LED4); // turn LED off to start out
while (1) {         
 if ((GPIOA->IDR & 0x0001) == 1) { // Debug: if USER button pushed, turn on both LEDs
 if (GPIO_ReadInputDataBit(GPIOB, INPUT_PIN1) == 0) {
  // State: Could be STRAIGHT or RIGHT
  if (GPIO_ReadInputDataBit(GPIOB, INPUT_PIN2) == 1) {
   // STATE: (1,0) Sensor tilting RIGHT -- first time
   while (BounceCheck < UNBOUNCE_CNT) {
    // If Debouncing is turned ON, check both inputs again
       if ((GPIO_ReadInputDataBit(GPIOB, INPUT_PIN1) == 0) && (GPIO_ReadInputDataBit(GPIOB, INPUT_PIN2) == 1)) {
     // Current State is still true (1,0) -- sensor is tilted right
     if (BounceCheck >= UNBOUNCE_CNT) {
      // STATE: Sensor tilt Right + sufficient re-checks of sensor made
      // TO DO: Check Direction of HW
      STM32vldiscovery_LEDOn(LED3); // turn Left LED on
      GPIO_WriteBit(GPIOC, OUTPUT_PIN1, Bit_SET); // PIN B1 right relay ON
    else {
     BounceCheck = UNBOUNCE_CNT; // Bust out of this loop;
  else {
   // STATE: (1,1) Sensor is STRAIGHT. Do Nothing.
 else {
  if (GPIO_ReadInputDataBit(GPIOB, INPUT_PIN2) == 0) {
   // STATE: (0,1) Sensor Tilting Left as we already know from first if statement that INPUT_PIN1 eq FALSE
   while (BounceCheck < UNBOUNCE_CNT) {
    // If Debouncing is turned ON, check both inputs again
       if ((GPIO_ReadInputDataBit(GPIOB, INPUT_PIN1) == 1) && (GPIO_ReadInputDataBit(GPIOB, INPUT_PIN2) == 0)) {
     // Current State is still true (0,1) -- sensor is tilted left
     if (BounceCheck >= UNBOUNCE_CNT) {
      // STATE: Sensor tilt LEFT + sufficient re-checks of sensor made
      // TO DO: Check Direction with Hardware
      STM32vldiscovery_LEDOn(LED4); // turn Right LED on
      GPIO_WriteBit(GPIOC, OUTPUT_PIN2, Bit_SET); // PIN B0 Left relay ON
      // Put inside loop b/c I only want it to delay when the relays on.
      // Otherwise program should go onto next input read cycle
    else {
     // STATE: Read (0,1) once but failed to read again.
     BounceCheck = UNBOUNCE_CNT; // Bust out of this loop;
 // Reset Everything back before starting the loop again...
 BounceCheck = 0;
 STM32vldiscovery_LEDOff(LED3); // turn LEDs off
 STM32vldiscovery_LEDOff(LED4); // turn LEDs off
 // Turn off Relays
 GPIO_WriteBit(GPIOC, OUTPUT_PIN1, Bit_RESET ); // Left Relay OFF
 GPIO_WriteBit(GPIOC, OUTPUT_PIN2, Bit_RESET); // Right Relay OFF

  * @brief  Inserts a delay time.
  * @param  nCount: specifies the delay time length.
  * @retval None
void Delay(__IO uint32_t nCount) {
   for(; nCount != 0; nCount--);