2020-01-25 10:23 PM
I imported a few projects from the STM32H7 firmware library; found a bug in the TFTP server application where the server is freeing a pbuf twice in some cases (easy to fix), made a few changes, then moved on to a new project, which is where everything went to pot.
I created the project for the STM32H742I-EVAL using the integrated configuration and project generator. It produced a project that took 3 hours to get to build because the tools didn't do the right thing with the middleware. Once it built, I discovered that I couldn't get the debugger to attach to the board, so I tried to duplicate the debug configuration from the first project I was running today. Nothing worked. I exited the IDE and started it again, but it didn't change anything.
I got tired, and went to put one of the projects I'd imported from the firmware library onto the board (I need it for testing something else), and it will not build. It can't find any of the files from the Drivers or Middleware anymore. I've tried everything I can think of except uninstalling the entire thing and reinstalling from scratch. I really don't want to have to do that. I spent over 14 hours today, missed lunch and dinner, and have NOTHING to show for it because the IDE is now unusable.
If there is anyone who knows how different projects (not in a project group) are corrupting each-others settings in STM32CubeIDE, I'd appreciate the letting me know. ASAP{, because I really need this to work, and it seems that STM32CubeIDE, currently version 1.2.1, is not quite stable.
2020-01-26 05:51 AM
Just to get it clear what you have done. You imported one project from the library. This project is under a name in the Project Explorer. I presume you where able to download with the debugger and run and step through the code? Then you created a project with CubeMX under a different name. Once you were able to build did you use Debug As? Why were you not able to return to the imported project by simply clicking on the name and download?
I found CubeIDE actually quite stable. Obviously it is build using Eclipse CDT as a base which sometimes can create headaches :)
2020-01-26 11:35 AM
Yes, I used "debug as" when I first tried to debug the "from scratch" project.
TL;DR for what follows: Eclipse appears to have corrupted the XML in either ".project" or ".cproject" when I opened then closed the projects while trying to load and debug my "original" (not imported) project. It did the same thing (roughly) for each of the imported projects, so I expect it was some sort of corruption in the Java managed data structures; newly imported projects don't exhibit the same problems, but I still can't build the old ones, having not yet figured out what settings are still corrupted.
Now the details.
The imported projects are linked from the firmware library directories rather than the files copied into the workspace; I found no way to get the "import from ac6" wizard to copy, it changes things in-place. Because of the way that the STM32CubeMX example projects are arranged, every project that I import always starts out with the same name (in this case, "STM32H743I_EVAL"), and I have to rename it before importing another one. Depending on the directory I choose in the import wizard, the project may be shown as nested under the application folder name, such as LwIP_TFTP_Server; the HTTP server application I imported from the SW4STM32 subdirectory, the others ("FatFs_uSD_DMA_RTOS" and "LwIP_TFTP_Server" I imported starting at the application directory under "C:\Users\actName\STM32Cube\Repository\STM32Cube_FW_H7_V1.6.0\Projects\STM32H743I_EVAL\Applications\{LwIP,FatFs}", but the project name itself always is "STM32H743I_EVAL" until I rename it. Renaming has gone fine.
So in my "Project Explorer" pane, I have "Ethernet-Proxy-Thing" (the from scratch project created in the "Device Configuration Tool" perspective), "FatFs_uSD_DMA_RTOS/SW4STM32/STM32H743I_EVAL-fatfs-usd-dma" (imported ac6 project from library), "LwIP_TFTP_Server/SW4STM32/STM32H743I_EVAL-tftp" (another imported project), and the aforementioned "STM32H743_EVAL-httpd_socket" (the first import I did). (While writing this, I added a new imported project, but I'm not going to add it here.)
My baseline "Ethernet-Proxy-Thing" project has the local code under "Core/{Inc,Src,Startup}", customized middleware code in appropriately named directories parallel to "Core" ("Drivers", "LWIP" and "FatFs", in this case), and the middleware sources that are not customized for the project under "Middlewares". The "Includes" folder in the project contains links to the toolchain headers from the IDE installation and the various source and include directories directly in the project. This is roughly what I am used to from the prior Eclipse-based IDEs I've used for stm32 development (Atollic, ac6).
The imported projects from the firmware library are rather differently arranged, but basically the same thing except that all of the files are linked to where they are in the firmware library, with no driver or middlware files as part of the project directories themselves.
Usually, I only have one project open at a time; I close all of the others to avoid confusion. I did this yesterday, but when I was having trouble with the debugger on my original project, I did open one of the imported projects so I could compare the debug settings. When I gave up with that, I closed all projects and opened the the "httpd" project (I've modified it to serve files from the uSD rather than only from a hard-coded FS and some other improvements to the HTTP support), and when I tried to "debug" it, the debug settings had somehow changed so that it always did a build before loading the program onto the device. I was surprised when it started to build all of the sources (I'd not changed anything that I knew of), and the build failed because it could not find the files in the firmware library. I looked at the properties for the files it wasn't finding. The "Type" shows as "Linked File", location is "copy_PARENT\Src\***" for files under the "Application/User" folder in the project , "copy_PARENT12\Drivers\STM32H7xx_HAL_Driver\Src\***" for things under the "Drivers/STM32H7xx_HAL_Driver" folder, and similar "copy_PARENTxx" values for others. The "Resolved location:" was non-existing files under the IDE install directory. I went to the project properties under the "Resource/Linked Resources" page in the "Path Variables" tab, and saw that "copy_PARENT" was defined as "$(ECLIPSE_HOME)" followed by what looked a bit like line noise, "copy_PARENT1" and "copy_PARENT12" were defined relative to "copyPARENT". After a lot of trial and error, I worked out that "copy_PARENT" is the path to the project files in the firmware library ("C:.\Users\danie\STM32Cube\Repository\STM32Cube_FW_H7_V1.6.0\Projects\STM32H743I-EVAL\Applications\LwIP\LwIP_TFTP_Server\SW4STM32"), and I changed it to that, but I still could not get the thing to build. I have created a new imported project (from the "Projects/Examples" directory in the FW library), and then looked at the properties for that; "copy_PARENT" is defined relative to the installation directory, so my project (as shown above) needs "copy_PARENT" to be defined as "${ECLIPSE_HOME}\..\..\..\Users\danie\STM32Cube\Repository\STM32Cube_FW_H7_V1.6.0\Projects\STM32H743I-EVAL\Applications\LwIP\LwIP_TFTP_Server\SW4STM32" instead. This gets a little farther in the build process, but now fails with fatal error "cmsis_os.h: No such file or directory". The file can be found by opening the directory "C:/Users/userName/STM32Cube/Repository/STM32Cube_FW_H7_V1.6.0//Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS" shown under the "Includes" folder, specified in the project properties "C/C++ Build/Settings", on the "Tool Settings" tab under the "MCU GCC Compiler/Include paths" configuration as "../../../../../../../../Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS". Since the file can be seen in the "Project Explorer" within the "Include" folder, I would think the compiler should be able to find it.
There is also a warning: "Invalid project path: Include path not found (C:\Users\danie\STM32Cube\Repository\STM32Cube_FW_H7_V1.6.0\Utilities\Log).".
So the root of my formerly building projects no longer building seems to be that something broke the project properties for the imported projects while I was mucking about trying to get my original project to build. Every one of them seems to have had some lines in the project XML files changed one way or another. I know of nothing I did to those files directly, and I've not inspected them (that way leads to madness, after all), but that's where these settings are all stored. I assume that the changes took place when I opened those projects to look at the debug, then closed them. Eclipse probably wrote changes to those files, and something got messed up. Because the import of the projects left the files in place in the FW library, all of my changes are in the FW library folders; I'm not at all sure I can re-import them if I delete the current projects because the ac6 projects have already been converted to STM32CubeIDE projects. I could copy all of the source files from those directories into local directories, then import them into a fresh project, but getting the project settings right for the drivers and middleware that is used in those projects is a bit of a challenge (ST Micro does not provide ".ioc" files for any of the "Projects" in the FW library, which would make life so much easier.)
2020-01-26 11:55 AM
As an aside, the "TFTP server" application under "STM32Cube_FW_H7_V1.6.0\Projects\STM32H743I-EVAL\Applications\LwIP\LwIP_TFTP_Server" has a bug in the file "Src\tftpserver.c" in the function "rrq_recv_callback()". It frees the pbuf pointed to by variable "p" conditionally at line 319, and always calls "pbuf_free()" on the same pointer right before the end of the function (approximately line 325, but I don't have the original to compare to right now):
/* if the last read returned less than the requested number of bytes
* (i.e. TFTP_DATA_LEN_MAX), then we've sent the whole file and we can quit
*/
if (args->data_len < TFTP_DATA_LEN_MAX)
{
/* Clean the connection*/
tftp_cleanup_rd(upcb, args);
pbuf_free(p);
}
/* if the whole file has not yet been sent then continue */
tftp_send_next_block(upcb, args, addr, port);
pbuf_free(p);
The fix is to avoid calling "pbuf_free(p)" a second time on the same instance of "p":
/* if the last read returned less than the requested number of bytes
* (i.e. TFTP_DATA_LEN_MAX), then we've sent the whole file and we can quit
*/
if (args->data_len < TFTP_DATA_LEN_MAX)
{
/* Clean the connection*/
tftp_cleanup_rd(upcb, args);
pbuf_free(p);
p = NULL; /* Fix: 'p' is no longer valid, make it obvious */
}
/* if the whole file has not yet been sent then continue */
tftp_send_next_block(upcb, args, addr, port);
if (p != NULL) /* Fix: Don't free *p if it's already been freed */
{ /* Fix */
pbuf_free(p);
} /* Fix */
2020-02-01 06:04 AM
Let's look at the whole rrq_recv_callback() function of ST's TFTP server...
void rrq_recv_callback(void *arg, struct udp_pcb *upcb, struct pbuf *p,
const ip_addr_t *addr, u16_t port)
{
/* Get our connection state */
tftp_connection_args *args = (tftp_connection_args *)arg;
if (tftp_is_correct_ack(p->payload, args->block))
{
/* increment block # */
args->block++;
}
else
{
/* we did not receive the expected ACK, so
do not update block #. This causes the current block to be resent. */
return; // Missing in ST's code!
}
/* if the last read returned less than the requested number of bytes
* (i.e. TFTP_DATA_LEN_MAX), then we've sent the whole file and we can quit
*/
if (args->data_len < TFTP_DATA_LEN_MAX)
{
/* Clean the connection*/
tftp_cleanup_rd(upcb, args);
pbuf_free(p);
return; // Missing in ST's code!
}
/* if the whole file has not yet been sent then continue */
tftp_send_next_block(upcb, args, addr, port);
pbuf_free(p);
}
Take a note on missing return statements in lines 16 and 28. Originally around line 16 comes empty else block. How did it happen? My guess:
"The HAL is production-ready and has been developed in compliance with MISRA C®:2004 guidelines..."
"MISRA C:2004, 14.7 - A function shall have a single point of exit at the end of the function."
Because of this at some point some brainless code monkey "improved" the code by removing the "bad" return statements.
P.S. That TFTP server is not production-ready anyway as it doesn't have timeout and retransmission capabilities.
P.P.S. Take a look on this: https://community.st.com/s/question/0D50X0000BOtfhnSQB/how-to-make-ethernet-and-lwip-working-on-stm32
2020-02-01 06:06 AM
It's still flawed as it uses upcb and args after cleanup.