Hi, I state that I am a new user of platformIO. I am trying this extension in order to replace IAR embedded workbench which does not exist for Linux, my main operating system. Unfortunately, trying to load a simple program that turns on a LED if a button is pressed, it fails. The microcontroller I am programming is a STM32F303VC. The problem I think is in the flash phase, even if it does not present any errors… This is because the same source used on IAR works.
The problem is precisely that the software claims to have been loaded successfully, but it has not.
If it helps, I’m using platformIO on vscode on both debian stable and testing.
I am attaching the screens where the firmware flashes, which I assure you works. what can I try?
I think rather the opposite, because flashing works as you’ve shown yourself. Otherwise there would be errors there.
IAR and GCC behave differently as compilers on the same code, so with most likelyness it’s in the code or the setup thereof. I’ve seen plenty of cases here where e.g. someone compiles code that worked in Keil with PlatformIO (GCC) and it doesn’t work, because it optimizes something out, or treats variables used in interrupts differently, etc.
A problem could also lie in the clock configuration for the board. You are using a Discovery STM32F303VC board, or something custom?
void main(){
RCC->IOPAEN=1;
RCC->IOPEEN=1;
GPIOE->MODER9=Output;
GPIOA->MODER0=Input;
while(1){
while(GPIOA->IDR0==0);
while(GPIOA->IDR0==1);
if(GPIOE->ODR9==1)
GPIOE->ODR9=0; //Accendo il led
else GPIOE->ODR9=1; //Spengo il led
}//end while
}//end main
And this is my library: typedef struct{
unsigned int CR;
unsigned int CFGR;
unsigned int CIR;
unsigned int APB2RSTR;
unsigned int APB1RSTR;
union{unsigned int AHBENR;
struct{
unsigned DMA1EN:1;
unsigned DMA2EN:1;
unsigned SRAMEN:1;
unsigned Res:1;
unsigned FLITFEN:1;
unsigned Res1:1;
unsigned CRCEN:1;
unsigned Res2:10;
unsigned IOPAEN:1;
unsigned IOPBEN:1;
unsigned IOPCEN:1;
unsigned IOPDEN:1;
unsigned IOPEEN:1;
unsigned IOPFEN:1;
unsigned Res3:1;
unsigned TSCEN:1;
unsigned Res4:3;
unsigned ADC12:1;
unsigned ADC34:1;
unsigned Res5:2;
};//END STRUCT ahbenr
};//end union AHBENR
unsigned int APB2ENR;
unsigned int APB1ENR;
unsigned int BDCR;
unsigned int CSR;
unsigned int AHBRSTR;
unsigned int CFGR2;
unsigned int CFGR3;
}RCC_Type;
typedef struct{
union{unsigned int MODER;
struct{
unsigned MODER0:2;
unsigned MODER1:2;
unsigned MODER2:2;
unsigned MODER3:2;
unsigned MODER4:2;
unsigned MODER5:2;
unsigned MODER6:2;
unsigned MODER7:2;
unsigned MODER8:2;
unsigned MODER9:2;
unsigned MODER10:2;
unsigned MODER11:2;
unsigned MODER12:2;
unsigned MODER13:2;
unsigned MODER14:2;
unsigned MODER15:2;
};
};
unsigned int OTYPER;
unsigned int OSPEEDR;
unsigned int PUPDR;
union{ unsigned int IDR;
struct{
unsigned IDR0:1;
unsigned IDR1:1;
unsigned IDR2:1;
unsigned IDR3:1;
unsigned IDR4:1;
unsigned IDR5:1;
unsigned IDR6:1;
unsigned IDR7:1;
unsigned IDR8:1;
unsigned IDR9:1;
unsigned IDR10:1;
unsigned IDR11:1;
unsigned IDR12:1;
unsigned IDR13:1;
unsigned IDR14:1;
unsigned IDR15:1;
};
};
union{ unsigned int ODR;
struct{
unsigned OR0:1;
unsigned ODR1:1;
unsigned ODR2:1;
unsigned ODR3:1;
unsigned ODR4:1;
unsigned ODR5:1;
unsigned ODR6:1;
unsigned ODR7:1;
unsigned ODR8:1;
unsigned ODR9:1;
unsigned ODR10:1;
unsigned ODR11:1;
unsigned ODR12:1;
unsigned ODR13:1;
unsigned ODR14:1;
unsigned ODR15:1;
};
};
/*
unsigned int BSRR;
unsigned int LCKR;
unsigned int AFRL;
unsigned int AFRH;
unsigned int BRR;
*/
}GPIO_Type;
#define Input 0
#define Output 1
#define Alternate 2
#define Analog 3
#define RCC ((RCC_Type*) 0x40021000)
#define GPIOA ((GPIO_Type*) 0x48000000)
#define GPIOE ((GPIO_Type*) 0x48001000)
However, I repeat that this test program works regularly.
Just FYI, by choosing to include the SPL framework you automatically pull in code from the SPL’s startup assembly code startup_stm32f30x.S and the Reset_Handler() (first functon that is executed)) from system_stm32f30x.c that will initialize the processor and memory, and the tries to initialize the clocks.
The flow here is
Reset_Handler()
-> Copy the data segment initializers from flash to SRAM
-> Zero fill the bss segment
-> call SystemInit()
-> init HSI
-> SetSysClock() [attempts to turn on HSE oscillator]
-> call main()
But that should be okay, it shouldn’t get stuck there.
However, I’m 99% sure that the situation that I hinted at before is happening: Compiler optimizatons.
I recommend that in your header file all register fields
Are marked as volatile, just like the STM’s SPL code does with __IO. Otherwise the compiler might try to optimize it and not execute your code correctly.
You can see that this is happening because if I take your header file and compile the firmware I get as a compilatin result
RAM: [ ] 2.3% (used 1132 bytes from 49152 bytes)
Flash: [ ] 0.7% (used 1792 bytes from 262144 bytes)
Building .pio\build\disco_f303vc\firmware.bin
however, when I replace your header file with this
so, everything is marked as __IO, and I recompile, I get
RAM: [ ] 2.3% (used 1132 bytes from 49152 bytes)
Flash: [ ] 0.7% (used 1844 bytes from 262144 bytes)
so, 52 more bytes have been added to the code. Those might the those instructions actually reading the register and not doing optimizations like reading it once and assuming it never changes (which GCC does since there’s no volatile on the variable).
I recommend you try the above header file.
Also, I see that you’ve flashed the firmware via the STLink. PlatformIO has built-in debugging capabilities, you can just set a breakpoint anywhere and “Run & Debug” tab at the left side to start debugging.
However, be careful: When using this, the firmware is also recompiled in debug mode (-Og instead of -Os), and then those exact compiler optimizations destroying your firmware previously may not appear in debug mode anymore.
Ok, replacing your header with the mine, it works fine. Thanks for the help.
@maxgerhardt:
Just FYI, by choosing to include the SPL framework you automatically pull in code from the SPL’s
startup assembly code startup_stm32f30x.S and the Reset_Handler()
I don’t need frameworks, in fact I would like not to download anything.
@maxgerhardt: When using this, the firmware is also recompiled in debug mode (-Og instead of -Os ), and then those exact compiler optimizations destroying your firmware previously may not appear in debug mode anymore.
So the firmware might works also with my header?
Maybe I didn’t understand correctly… in fact I’m trying, but with my header file, it doesn’t work even in debug…
As per docs, with build_flags and build_unflags. (First remove the default -Os, then inject another).
However, you really really don’t want to do that for production code. Relying on a compiler optimization level or behavior for working code is bad, the code needs to be correct in the first place. And the code will be correct if registers are marked as volatile, as per above, that’s how all the SDK vendors (STM32 HAL etc.) are doing it. Compiling with -O0 also makes the code extremely slow.