Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added initial support to STM32 (using CubeHAL API). #863

Closed
wants to merge 1 commit into from

Conversation

colombojrj
Copy link

This commit adds initial support to the STM32 when using the CubeMX/CubeIDE/CubeHAL software or API, i.e., not Arduino like interface or API. This code was tested with the STM32F103C8T6 microcontroller.

@2bndy5
Copy link
Member

2bndy5 commented Aug 16, 2022

Have you read our docs about porting this lib to non-Arduino API? The whole point of using the utility folder is to keep hardware specific SDK API out of RF24.cpp and RF24.h

I think if you follow the template provided in the utility/template, then some of the additions to RF24.cpp, RF24.h, and RF24_config.h can be properly abstracted.

Is there a way we could test compile this in CI, so we know future contributions won't break this? I wouldn't mind a new separate workflow (like we did for the Pico SDK - see build_rp2xxx.yml).

Sadly, I don't have a STM32 board to test this on. So, I can't confirm this physically.

@colombojrj
Copy link
Author

Hi, I have seen that documentation, but I could not think of a way of porting the digitalWrite to the CubeHAL API because it uses two variables to describe a pin (the number and a handle struct). However, after a second thought, I think I could edit that gpio class to hold those two variables and then the problem would be solved.

I will try to write some code. If you need to test it, you could buy the bluepill board+stlink, they are very cheap (2 dollars + shipping). I do not understand much of yml files, but I will try also.

Soon I will come back with news. Seeya. And thanks for the library, it is very useful.

@2bndy5
Copy link
Member

2bndy5 commented Aug 16, 2022

I was actually considering the STM32F4 series (likely a black pill). I already have a debugger board.

Can you provide some links to the SDK (like docs/download)? I'd be better equipped to help with the yml/CI then.

@colombojrj
Copy link
Author

Hi, yes I can. The F4 is very powerful. The easiest kit consists in using STM32CubeIDE. You can also use CMake with these microcontrollers, but I would let that for later.

@2bndy5
Copy link
Member

2bndy5 commented Aug 16, 2022

I ordered a black pill from AliExpress for $9. I prefer to have gone with a more official distributor because AliExpress (& other amazon-like stores) are littered with DIY electronics clones (which often cut corners when it comes to power circuits).

You can also use CMake with these microcontrollers, but I would let that for later.

CMake is exactly the approach I aim to take with the CI; we can't install apps in CI that depend on using a GUI. I also want to make sure that this contribution won't affect the stm32duino core (assuming it uses the same SDK).

I will try to write some code.

Take your time with the rewrite. I won't be able to test this until my black pill comes (estimated mid September). I've also gotta learn how to use the SDK (CMake is typically my preferred build option).


I don't mean to be overbearing, and I think I tend to be with new contributors. I really am here to help because we do have some conventions that contributions should follow. BTW, the CI workflows (which use github actions) should tell you if your code broke something or doesn't fit with our code style, so I highly recommend you enable github actions for your fork before pushing another commit.

@colombojrj
Copy link
Author

Hi, you are not overbearing. You are actually very kind.

About the stm32 mcu: some time ago, I have bought 10 bluepills and ... all of them were fake. It is very frustrating. From now on, I am using only the Nucleo boards sold by mouser/digikey. If you want to learn about the CubeHAL api, I may recommend two good course on udemy, here and here.

I decided to try to push initial support to STM32 because I was losing code every time this library gets updated. Now, I am very proud of my last piece of code because, for the first time, I was able to build this library without any change to RF24.h, RF24.cpp and RF24_config.h (although I cheated and created includes manually, but I do not care for this). Even if the new code is not acceptable for publishing it here, I am very happy with it because from now on, I will only copy new updates into the library. Anyway, thanks.

What have I done:

  1. I defined an enum (rf24_pin) with all pins that could be possible to be used (from port A to G, with 16 pins each). Then I added a static function to decode the pin port and number from it. It uses rest of division and integer division to be quick and do not increase the code footprint too much. This solves the gpio problem.
  2. I defined a SPI class (RF24_SPI) that contains only a pointer to the spi handler of ST API and three methods: begin(void), begin(handler*) and transfer(uint8_t). The user must configure the SPI before calling begin(handler*) manually. This is the default procedure with the ST API. Then the user may initialize the radio as described in the documentation. Otherwise it will not work.

The STM32 mcu may have more than one SPI, so it is nice to let the user to decide what spi to use.

About the CMake: I use CMake, but I am now very good at it. I really spent some time reading your CMake files, and it is too much sophisticated for me. So, I wrote some few lines to build the rf24 static library.

I also verified a small inconvenient: I have completely forgotten about a dependency of the CubeHAL. It requires a configuration file ("stm32f1xx_hal_conf.h") that is deeply connected to the application code. So it is valid to assume that the library will not be able to be built alone, only with application code. I do not know if this is a problem.

Finally, the library was tested and the radio ... worked! I will wait for your reply to decide how to proceed.

My best regards.

@2bndy5
Copy link
Member

2bndy5 commented Aug 17, 2022

Even if the new code is not acceptable for publishing it here, I am very happy with it because from now on

I want this to get accepted! This kind of contribution is exactly what we look forward to! Thanks for all the informative links too. It looks like what I would consider an STM32 SDK is split up into framework components. The docs for these components seem sparse without looking at the code. I haven't registered an account with the STM32 site yet, so I haven't downloaded anything yet (kinda weird that they require that).

What have I done: ...

  • Point 1 sounds fair if the STM32Cube framework doesn't define board specific defaults, and I can't imagine that they would with all the numerous clones out there.
  • Point 2 seems on the right track. RF24.cpp will make use of SPIClass::begin/endTransaction() if SPI_HAS_TRANSACTION macro is defined. The main purpose for that function is to better manage different SPI bus settings for different devices on the same (or multiple) SPI buses.

    RF24/RF24_config.h

    Lines 221 to 224 in 89358b2

    #if defined(SPI_HAS_TRANSACTION) && !defined(SPI_UART) && !defined(SOFTSPI)
    #define RF24_SPI_TRANSACTIONS
    #endif // defined (SPI_HAS_TRANSACTION) && !defined (SPI_UART) && !defined (SOFTSPI)

The STM32 mcu may have more than one SPI, so it is nice to let the user to decide what spi to use.

I can help with that as I introduced the overloaded RF24::begin(_SPI*). But, I need to see the your code changes first (just to know what I'm working with).

I have completely forgotten about a dependency of the CubeHAL. It requires a configuration file ("stm32f1xx_hal_conf.h")

I was just looking at the platformIO integration for the STM32Cube framework, and it looks like this is handled like a build environment variable (which probably translates into a -I flag).

So it is valid to assume that the library will not be able to be built alone, only with application code. I do not know if this is a problem.

This answer is going to be a little daunting, but we usually create a new example folder for this purpose. If it isn't too much trouble, I'd like to get a port of the GettingStarted example to a new folder called examples_stm32 (at repo root). It is preferable to use as much native code from STM32Cube framework as possible (aside from the code that exemplifies using RF24).

I had to do the same thing for the PicoSDK. Beneficially, once the CI is up and running, we can get the build artifacts from the workflow and flash them directly to the MCU (the build_rp2xx.yml produces both elf and hex artifacts for most boards supported). In the case of building these artifacts for different boards, I used a default_pins.h in the examples_pico/ that streamlines the default pins used for the radio. The pico SDK actually has default SPI pins defined for each supported board, so this examples_stm32/default_pins.h may be quite different. However, the default_pins.h idea is completely optional (the Arduino examples don't do this for simplicity).

@colombojrj
Copy link
Author

Hi, today was a busy day. I finished uploading the latest code here. The spi class may be considerably improved, for example, by checking if the pointer is valid (i.e., not nullptr) before calling the st api.

The radio initialization would be something like:

// global variable
RF24 radio;

// main
_SPI.begin(&hspi1);
radio.begin(rf24_pin::RF24_PB0, rf24_pin::RF24_PB1);

I will try to rewrite the examples. Seeya.

@2bndy5
Copy link
Member

2bndy5 commented Aug 18, 2022

If there's a way to detect that the STM32Cube framework is being used by CMake (like a defined CMake variable), then we can simply add a condition at the top of the root CMakeLists.txt file that forwards the process to the utility/STM32/CmakeLists.txt (which would basically be the CMakeLists_required_to_stm32.txt that you put in the repo's root).

We do the same thing for the PicoSDK (using the CMake variable PICO_SDK_PATH):

RF24/CMakeLists.txt

Lines 1 to 7 in 89358b2

# Check if we are building a pico-sdk based project
# (or more exactly: if we just got included in a pico-sdk based project)
if (PICO_SDK_PATH)
# If so, load the relevant CMakeLists-file but don't do anything else
include(${CMAKE_CURRENT_LIST_DIR}/utility/rp2/CMakeLists.txt)
return()
endif()

Everything else in that root CMakeLists.txt file is for Linux only.

@2bndy5
Copy link
Member

2bndy5 commented Sep 7, 2022

I just soldiered pins to my STM32F4 board, and I'm still playing around with it. I needed STM32CubeProgrammer installed to flash circuitpython to it over USB...

I going to merge your latest branch stm32-support into a branch on this repo (called "stm32cube"), so I can start playing around with your changes - the main intention is to keep your git history intact, so your good work is properly attributed. I'm leaving this PR open as reminder. Unfortunately, we cannot merge this support into the master branch yet. When I clone your stm32-support branch to upstream here, I will close this PR and open an issue to continue discussions.

I'll keep you posted...

@colombojrj
Copy link
Author

I have never flashed a stm32 through usb, but that sounds great. If you successes, please tell me. I was looking at the RF24 examples and one issue is the print/printf function. Although they are existed because of stdio.h, they are not implemented. I have found this post about how to enable the basic stdio functions in stm32 where they implement the low level mechanism of printf.

What do you think?

@2bndy5
Copy link
Member

2bndy5 commented Sep 7, 2022

I have never flashed a stm32 through usb, but that sounds great.

STM32F103 doesn't ship with a DFU capable bootloader, so I'd be surprised if the blue pill can be flashed over USB. The Arduino cores seem to have worked around this by using a HID-based soft bootloader that looks for a magic value and resets the board. I tried for hours trying to get that working on my STM32F4, but I gave up... I'll likely only use PlatformIO with the Arduino framework for this board.

Although they are existed because of stdio.h, they are not implemented. I have found this post about how to enable the basic stdio functions in stm32 where they implement the low level mechanism of printf.

I don't really know the STM32Cube framework that well yet. Initially, I'd recommend using sprintfPrettyDetails() instead, but that may not be preferable for some users.

@2bndy5 2bndy5 mentioned this pull request Sep 9, 2022
3 tasks
@2bndy5
Copy link
Member

2bndy5 commented Sep 9, 2022

discussion is continued in #872

@2bndy5 2bndy5 closed this Sep 9, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants