Search code examples
armembeddedstm32microcontrolleropenocd

stm32 build from scratch successfully flashes but doesn not run on the board


I am new to building projects from scratch with mcu's. I took an old project file that successfully runs in an eclipse/gdb build environment where the IDE does all the building for me and tried implementing my own build using open-ocd and the toolchain: arm-none-eabi. I was successful in flashing the device, however the board does not run the code. I was hoping that I could potentially be missing some obvious important file, but I have not come to that conclusion.

My main concern is that I do not have a proper set up for my start_up.c file or linker.ld file, though I have not found a reason to believe so. I am using the stm32L476 discovery board. Here is a link to the data sheet if anyone is interested: https://www.st.com/resource/en/reference_manual/dm00083560-stm32l47xxx-stm32l48xxx-stm32l49xxx-and-stm32l4axxx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf

My sources to my problem are here in github: https://github.com/landonbr/stm32-fun


Solution

  • I strongly recommend that you do not use C to bootstrap C. And strongly recommend not using structures across compile domains.

    • 96 Kbyte mapped at address 0x2000 0000 (SRAM1) • 32 Kbyte located at address 0x1000 0000 with hardware parity check (SRAM2).

    On STM32L49x/L4Ax devices, the SRAM2 is aliased at address 0x2004 0000, offering a continuous address space with the SRAM1.

    This is an STM32L47 yes? So that does not apply.

    08000000 <vector>:
     8000000:   20020000    andcs   r0, r2, r0
     8000004:   0800043b    stmdaeq r0, {r0, r1, r3, r4, r5, r10}
     8000008:   08000435    stmdaeq r0, {r0, r2, r4, r5, r10}
     800000c:   08000435    stmdaeq r0, {r0, r2, r4, r5, r10}
    

    0x200000 = 128Kbytes. Try something small just to get started 0x20001000. Or go for the 96K. 0x20018000

    It is not broken (well it can be depends on the register and field) but cleaner to do the read-modify-write separate from the register so the register only goes from one mode to another rather than switches modes twice.

    GPIOB->MODER &= ~(3UL<<4);    // Clear mode bits​
    GPIOB->MODER |= 1UL<<4;       // Set mode to output​
    
    
    tmp = GPIOB->MODER
    tmp &= ~(3UL<<4);    // Clear mode bits​
    tmp |= 1UL<<4;       // Set mode to output​
    GPIOB->MODER = tmp
    

    It may be a good idea to do one thing at a time. Either just turn on an led or blink the led using a counter based delay (that is not dead code). Then later mess with buttons or timers or whatever.

    Take a look at the gpio BSRR register instead of ODR. Makes life easier.

    This is dead code,

        if(Upush%2!=0){
            GPIOE->ODR &= ~(1UL << 8);
            for(int i=125000; i!=0; i--){}
            GPIOE->ODR |= (1UL << 8);
            for (int i=125000; i!=0; i--){}
        }
    

    It compiles into this basically

        if(Upush%2!=0){
            GPIOE->ODR &= ~(1UL << 8);
            GPIOE->ODR |= (1UL << 8);
        }
    

    Which is too fast to see without a scope. And you cannot really determine the time in the loop so it is not 2 Hz.

    In your case you did not optimize so that loop is in there it appears at least with the gnu I am using.

    Granted you should start with this:

        while(1){
            GPIOE->BSRR = 1<<(8+16);
            for(volatile int i=125000; i!=0; i--){}
            GPIOE->BSRR = 1<<(8+ 0);
            for (volatile int i=125000; i!=0; i--){}
        }
    

    as your main program after init of that gpio pin. Without any of the joystick buttons stuff. Get that working and insure that your basic skeleton is good, then add stuff to it. (note buttons are tricky/painful as you often want to debounce them. Likely not in this case, but in general)