Did you make sure that you compiled your code for the correct MCU? It looks like this board comes in at least two different models; if you're compiling against the wrong processor, it's possible that your code is just erroring out right away and halting the CPU. You could also try to debug the code to see if it runs and where it hangs.
There are links to schematics on this page as well..
https://stm32world.com/wiki/Black_Pill
It's possible but what I'm mostly curious about is why the LED no longer lights when I connect the board to USB-C. It originally did and the LED would go off when you'd enter DFU mode. Entering DFU mode still works but there is no LED. Is there some form of "bootloader" that I've overridden with my code? I've read various mentions of Arduino compatible "bootloaders" etc.
I assume that you're talking about the user LED here… at boot, that GPIO pin is held floating and needs to be turned on via code in order for the LED to light. Therefore, the CPU is halting before it gets to the point where the code instructs the LED GPIO pin to go high. Most likely, this is because you've either:
Originally, before I flashed anything. If the device was connected to USB-C, both the user and POWER LEDs would be lit. The user LED (next to C13) would go off after I entered DFU mode (POWER LED remained on).
Since flashing the code (which it's possible is bad) when I connect to USB-C, the user LED no longer comes on but I can still enter DFU mode.
EDIT: I will look at the code I'm flashing some more, verify it's correct. It's supposed to blink PC13 but I was unsure what was going on wrt above?
What was happening before you flashed the device is that there was already some code on it that was booting properly turning on the LED.
I was trying to avoid using the bloatware STM gui but perhaps it might be better initially as there are more examples using that.
I was trying to avoid using the bloatware STM gui but perhaps it might be better initially as there are more examples using that.
I was trying to avoid using the bloatware STM gui but perhaps it might be better initially as there are more examples using that.
My suggestion is to use CubeMX to get started,
(...) I was able to select the C13 pin but my efforts to "generate code" keep resulting in popups asking me which external program I want to use to open this .project file (...)
Use CubeIDE instead. Basically, it's Eclipse + CubeMX.
Try the attached project, flash the precompiled .bin file inside Release folder.
The LED blinks now
I'm still much happier working with emacs, bash and gcc .... so I'll work towards that goal.
Some dinosaurs still argue emacs/text editor is the way to go...
But no thanks, it's like saying hand-made iron smelting in clay furnaces by sweating slaves is better than modern industrial techniques .
- Real-time syntax checking just great, makes your life easier. I appreciate my time, with a simple text editor, you won't notice if you accidentally typed "rpintf" until compiling.
- Control+click and mouse hovering are great to have a quick glance/fly to the declaration/definition, it's incredibly useful, otherwise you hav to remember everything.
- Embedded debugging, variables, expressions, all-in-one package makes it extremely simple to setup...
- Making Makefiles by hand? Erm, no thanks, I already waste a lot of time with those heeecking registers and buggy peripherals
Some dinosaurs still argue emacs/text editor is the way to go...
You *don't* have to keep all the mess updated. In fact I'm reluctant to, too much bad stories, strong as thin glass.
/*
* Force host to re-enumerate device
*/
GPIO_InitTypeDef GPIO_InitStruct = { 0 }; // All zeroed out
GPIO_InitStruct.Pin = GPIO_PIN_12; // Hardcoding this - PA12 is D+
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // Push-pull mode
GPIO_InitStruct.Pull = GPIO_PULLDOWN; // Resetting so pull low
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; // Really shouldn't matter in this case
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // Initialize with above settings
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_12, GPIO_PIN_RESET); // Yank low
HAL_Delay(50); // Enough time for host to disconnect device
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_12, GPIO_PIN_SET); // Back high - so host will enumerate
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_12); // Deinitialize the pin
[platformio]
src_dir = ./
[env:stm32f407_nand]
platform = ststm32
board = vccgnd_f407zg_mini
framework = stm32cube
src_filter = +<Core/Src/*>
+<USB_DEVICE/App/*>
+<USB_DEVICE/Target>
monitor_port = com4
build_flags =
;-D__STATIC_INLINE=
-DVECT_TAB_OFFSET=0
-Wunused-variable
-DDEBUG
-ffunction-sections
-fdata-sections
-funroll-loops
-Wl,--gc-sections
-Wno-implicit-function-declaration
-ICore/Inc
-IUSB_DEVICE/App
-IUSB_DEVICE/Target
-IMiddlewares/ST/STM32_USB_Device_Library/Core/Inc/
-IMiddlewares/ST/STM32_USB_Device_Library/Class/Inc
-DHSE_VALUE=8000000
For IDE i find that Visual studio+platform io works great for me, here is my normal work flow.
....
On the project manager page I normally select Makefile as Toolchain IDE as i often am in linux or WSL and typing "make clean && make " is quick for my brain , it also makes for a handy reference needed later (no pun intended)
....
Next I load platformio (visual studio+platformio) and select open folder, browse to the folder with Makefile and platformio and let the platformio backend load up.
I understand better now the distinction between CubeMX and CubeIDE though it still feels "messy" to have to invoke CubeMX and then import this into PlatformIO, though obviously doing everything bare metal like I was trying is complicated++.
A particular vendor spin of eclipse I use at work will sometimes throw a Java exception when hovering over some items in the toolbar and bring the whole thing to a halt. I LOVE eclipse.
The whole setup with the HAL where you have to fill a structure with the intended settings, and then call the needed functions to make things work, it takes certainly less code space when you write to the peripheral registers directly.
typedef struct {
GPIO_TypeDef* port;
LL_GPIO_InitTypeDef init;
} GPIO_Init_t;
const GPIO_Init_t GPIO_cfg[] = {
{ SWC_Port, { SWC_Pin, LL_GPIO_MODE_ANALOG }},
{ SWD_Port, { SWD_Pin, LL_GPIO_MODE_ANALOG }},
{ PWM_Port, { PWM_Pin, LL_GPIO_MODE_ALTERNATE, LL_GPIO_SPEED_FREQ_VERY_HIGH, LL_GPIO_OUTPUT_PUSHPULL, LL_GPIO_PULL_NO, PWM_AF }},
{ CCP_Port, { IR_Pin, LL_GPIO_MODE_ALTERNATE, LL_GPIO_SPEED_FREQ_VERY_HIGH, LL_GPIO_OUTPUT_PUSHPULL, LL_GPIO_PULL_NO, IR_AF }},
{ RED_Port, { RED_Pin, LL_GPIO_MODE_OUTPUT, LL_GPIO_SPEED_FREQ_VERY_HIGH, LL_GPIO_OUTPUT_PUSHPULL }},
};
for(uint8_t i=0; i<sizeof(GPIO_cfg)/sizeof(GPIO_Init_t); i++)
LL_GPIO_Init(GPIO_cfg[i].port, (LL_GPIO_InitTypeDef*)&GPIO_cfg[i].init);
ErrorStatus LL_GPIO_Init(GPIO_TypeDef *GPIOx, LL_GPIO_InitTypeDef *GPIO_InitStruct)
{
uint32_t pinpos;
uint32_t currentpin;
/* Check the parameters */
assert_param(IS_GPIO_ALL_INSTANCE(GPIOx));
assert_param(IS_LL_GPIO_PIN(GPIO_InitStruct->Pin));
assert_param(IS_LL_GPIO_MODE(GPIO_InitStruct->Mode));
assert_param(IS_LL_GPIO_PULL(GPIO_InitStruct->Pull));
/* ------------------------- Configure the port pins ---------------- */
/* Initialize pinpos on first pin set */
pinpos = 0;
/* Configure the port pins */
while (((GPIO_InitStruct->Pin) >> pinpos) != 0x00u)
{
/* Get current io position */
currentpin = (GPIO_InitStruct->Pin) & (0x00000001uL << pinpos);
if (currentpin != 0x00u)
{
/* Pin Mode configuration */
LL_GPIO_SetPinMode(GPIOx, currentpin, GPIO_InitStruct->Mode);
if ((GPIO_InitStruct->Mode == LL_GPIO_MODE_OUTPUT) || (GPIO_InitStruct->Mode == LL_GPIO_MODE_ALTERNATE))
{
/* Check Speed mode parameters */
assert_param(IS_LL_GPIO_SPEED(GPIO_InitStruct->Speed));
/* Speed mode configuration */
LL_GPIO_SetPinSpeed(GPIOx, currentpin, GPIO_InitStruct->Speed);
}
/* Pull-up Pull down resistor configuration*/
LL_GPIO_SetPinPull(GPIOx, currentpin, GPIO_InitStruct->Pull);
if (GPIO_InitStruct->Mode == LL_GPIO_MODE_ALTERNATE)
{
/* Check Alternate parameter */
assert_param(IS_LL_GPIO_ALTERNATE(GPIO_InitStruct->Alternate));
/* Speed mode configuration */
if (currentpin < LL_GPIO_PIN_8)
{
LL_GPIO_SetAFPin_0_7(GPIOx, currentpin, GPIO_InitStruct->Alternate);
}
else
{
LL_GPIO_SetAFPin_8_15(GPIOx, currentpin, GPIO_InitStruct->Alternate);
}
}
}
pinpos++;
}
if ((GPIO_InitStruct->Mode == LL_GPIO_MODE_OUTPUT) || (GPIO_InitStruct->Mode == LL_GPIO_MODE_ALTERNATE))
{
/* Check Output mode parameters */
assert_param(IS_LL_GPIO_OUTPUT_TYPE(GPIO_InitStruct->OutputType));
/* Output mode configuration*/
LL_GPIO_SetPinOutputType(GPIOx, GPIO_InitStruct->Pin, GPIO_InitStruct->OutputType);
}
return (SUCCESS);
}