Skip to main content
luch
Associate II
February 8, 2019
Question

Is there another way?

  • February 8, 2019
  • 14 replies
  • 2899 views

I am a very patient man. I've spent the last 2 days (not hours! entire days!) studying this 'simple' example from Cube1 (HAL_TimeBase_RTC_ALARM). The example is irrelevant: I've experienced the same with other examples...

So, I'm looking at these files, started digging from main and the rabbit's hole took me very, very far... I found things that are not even mentioned in the (i.e.) Reference Manual... but I digress.

I've been fighting, trying to make some sense of it, with a wall of 38 files and 28064 lines, standing between me and the micro. And this is just a little example program! I am jumping thru this mountain of 'define's and going nowhere. There are people really determined to declare and name and rename and rename and rename things to death. What I don't see on these screen is 'action'. Or real C!

At the end of the day(s) one could gather all that blah-blah-blah (isn't HAL suppose to make our life easier?!) into a handful of instructions that would fit on a screen!

Are all of you, guys and girls, going thru the same? How do you deal with all this sh..oftware?

Is there another way? Or am I just stupid?

    This topic has been closed for replies.

    14 replies

    Tesla DeLorean
    Guru
    February 8, 2019

    I learned many years ago that people all think and approach things differently.

    HAL is a bit of a train-wreck, there are portions that are usable, and other portions and idea need to be taken to the middle of a field and burned. The original SPL abstraction was relatively clean and simple, whereas HAL tries to unify differences in architectures, and applies a paradigm that doesn't always fit will with other embedded solutions/methods. Races conditions, locking, thread safety and priority inversion touch the surface of some of the issues I don't think have been fully addressed.

    I take HAL, use the pieces I can work with, and refactor or replace the pieces I can't. For example the USART implementation, only the initialization is worth touching. I'll let the compiler and linker do dead code elimination on the rest.

    I can do register level programming, but this isn't an 8-bit micro, and I'm not going to fill my head with 10,000 manual pages.

    I've got good static analysis tools, methods, and skills, and a clear understanding of what the underlying silicon is doing.

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    luch
    luchAuthor
    Associate II
    February 9, 2019

    Thanks Clive,

    yep, people do things differently (I don't know about the thinking part), that's why the diversity of tools around these micros. I don't have any preferences yet, as long as I am totally new to HAL, LL, CMSIS & co. What I'm trying to do is to avoid wasting time on things that are not worth it and I might not use in the long run and to focus on those that count: ARM architecture, programming, peripherals, etc. Yes, I'm coming from the 8 bits world (Atmel/Microchip), where one doesn't need to learn 'tools' that introduce an extra layer of abstraction to make things more 'universal', more 'portable', more fancy. Why should I write 200 lines of C, when I can use HAL and deal with 20000?! Maybe it's my lack of experience but I don't feel in control when I have to handle tens/hundreds of files with tens of thousands of lines and to generate an executable from which less than 5% is my contribution.

    You, like you said, have the skills, the methods and the understanding not only of the silicon, but the entire environment. You can, therefore, make a determination as to what is the appropriate tool to use in a certain situation, because you already know them - their good and not so good parts. I'm not there yet. I'm just trying to find out how other people are doing things, what should I learn first and what not.

    I know there is no easy way to master this. There is a lot to take in and nobody can do it for me - I'd just like to avoid the pollution...

    waclawek.jan
    Super User
    February 9, 2019

    I here openly represent the extreme end of the spectrum, those who do not use any "library".

    I started with spending days (not hours) reading the manuals; have written dozens of simple testing programs for the peripherals I intended to use and played with them around (and I still do); and that was it.

    > Why should I write 200 lines of C, when I can use HAL and deal with 20000?!

    The peripherals are very complicated, as transistor size is small so many of them fit to the chip, and the design process is very much like programming these days, far from stitching together circuits from transistors or gates, so creating that complexity is quite easy. However, most of the peripherals have a simple core where one can start - take for example a timer, you enable its clock in RCC, set some value into TIMx_ARR, set TIMx_CR1.CEN and that's it. Want interrupt? Enable in TIMx_DIER and enable in NVIC and write a handler. This is not much different from what we do in the 8-bitters.Want PWM output? Set some value into TIMx_CCRy, chose the appropriate mode in TIMx_CCMRy., enable in TIMx_CCER, and that's it. Oh wait, you also need to set the appropriate pin in GPIO as AF and set it's proper AF (and before that all enable GPIO's clock in RCC) - but you've already learned how to do all this when you played with the basic loopdelay-blinky.

    So, handling the basic features of one peripheral is maybe a dozen of lines in C, not hundreds. And the rest offered by Cube - interrupt handlers, using circular buffers, moving data around, taking care of atomicity and other interrupt-related issues (or you can read it as thread-related or inter-process related, if you are into multitasking aka RTOS) is all basic programming skills, little to do with microcontrollers as such.

    So, what a novice really needs are clear and well-described examples, which can be used as basis for the single most powerful and most underestimated programming method, copy-pasting. And he needs dozens if not hundreds of them for every single peripheral.

    Now the problem is, that the basic documentation (DS/ES, RM, PM, ARM's material) is not very clear and examples for this sort of programming are scarce(ST started and then also promptly killed Snippets, available in sort of a beta state for F0 and L0 only). OTOH, the documentation for Cube/HAL/LL is also not the clearest (mostly doxygen-autovomited thus not very useful), and as you've said, the examples are also not exactly easy to understand (thus make them as a basis for further work). And, at the end of the day, there is not that many of those examples out there in Cube.

    HAL (the "abstraction" part in it) promises portability. I freely admit I can't judge this - I never needed much of that - most of the peripherals in STM32 are the same or very similar across sub-families, and while there are exceptions - I2C, notably - I have no problem reading just one more chapter from the manual and write the software accordingly.

    OTOH, "abstraction" inevitably means to find a least common denominator, and implement only a limited subset of what the hardware really allows (and it also inevitably means loss of efficiency of all kinds, but whether it's significant, well that's for another discussion). That's mostly OK as that subset obviously represents the most common usage modes. But once you want to depart from them, well, you're on your own, doing that drilldown and decomposition and figthing against the "native" HAL features - plus you'll have to learn *both* the Cube innards *and* the chip's exact workings, and remember not only the 1000 pages of manual and 1000 Cube-invented names for individual features, but also the mapping from one to the other.

    Another promise of the "libraries" is instant access to the more complex peripherals - USB, ETH. Whether it's worth to use them, or to invest time to write your own or invest money into purchasing third-party, well, that's the question of having a deeper look at all those offerings...

    Cube also promises easy setup through CubeMX, but that also means certain dependence on CubeMX and its quirks and its - as witnessed by threads in this forum, at times surprising - variablily through upgrades.

    Then there of course are bugs, in CubeMX and in Cube/HAL/LL. This is not to blame the Cube/CubeMX authors, we all write bugs at a higher rate than we are willing to admit. I personally just prefer my own bugs to others'... :D

    2 eurocents.

    JW

    turboscrew
    Senior III
    February 9, 2019

    I usually read the reference manual or ARM ARM for that architecture (if it's core peripheral).

    Then I see how I can make HAL to do it for me. I'm more into register level programming, but I have to use CubeMX (policy at work). Also, HAL doesn't support everything the HW supports. I generate the code with CubeMX and change the set up with code in "user begin / user end" sections. There are usually also macros to flip the bits you need to flip.

    With RTC (using stabdby mode) I had to generate the code, copy the code to another place and disable RTC from Cube and generate the stuff again and then add calls to initializations manually to prevent RTC initialization every time the board wakes up from stabdby.

    So, to me, using CubeMX usually means a "layer" of extra work, but since I have to...

    luch
    luchAuthor
    Associate II
    February 9, 2019

    Thanks turboscrew!

    CubeMX seems to be a great help, although it is even more controversial than HAL. As a matter of fact I've just downgraded it a couple days ago, from 5.x to 4.27 because the UI of 5 *****.

    So, from what I understand, I have to get accustomed with HAL & co. You are far more advanced: change the setup code generated by HAL with your own! How? How does that looks like? What language/library... With the next paragraph you lost me completely, but I understand there is no easy/strait way to write software with these tools. Just pain!

    Pavel A.
    February 9, 2019

    > but I understand there is no easy/strait way to write software with these tools. Just pain!

    ​There are different sorts of people. For example I often don't know how to fix my car or what's wrong with it at all. So I go to a garage and they fix it.

    Like that, you can outsource all the "pain" of low-level coding to a professional who knows it, and skip straight to things you want to do.

    So all the hairwire HAL and stuff become for you just platform_initialize() and that's it! No suffering.

    Does it make sense?

    If you prefer to do everything alone, bake your bread - there are other small platforms that come with complete software stack - Raspberry Pi's, Beaglebones etc.

    -- pa

    luch
    luchAuthor
    Associate II
    February 10, 2019

    Thanks for the advice Pavel!

    To put it simple, I just want to learn now... and I don't think I can 'outsource' that. I don't mind the pain. I'm just trying to avoid unnecessary pain. The 'platform_initialize()' part is already done pretty well by CubeMX, that is the main purpose of it, isn't it?

    I am not doing everything alone (although, I wish could): I am here, right? asking for help/advice from people with experience, who have been thru this pain and confusion more or less, at some point. I am trying to gain from their/your experience, so I can avoid the pitfalls of wasting time by going in the wrong direction and focusing in unimportant things.

    And I'm doing this as a hobby, I am not a business, I don't have a deadline, no 'time to market', not making money out of it. As most hobbyists, I am investing my time and money in this, with the gain of learning and making things on my own.

    Willunen
    Associate III
    February 10, 2019

    Yes, we are all going through (or went through) the same process. I'm a hobbyist too and I too came from the AVR world (and long ago the Motorola world) In the AVR world I ran away from the Arduino libraries as soon as possible as those too were unreadable for me and I wrote to the bare registers.

    When I migrated to the STM32's I wanted to do the same, using CMSIS. So like this "TIM1->DIER |= TIM_DIER_UIE;" This makes you have to read the Reference Manual AND the CMSIS "libraries" very well.

    After some time I discovered STM32CubeMX which I first used for the pinout only. Later I tried the HAL code but didn't like it. I bought a book "Mastering STM32" by Carmine Noviello only to find out he uses the HAL exclusively. So I went on using CMSIS.

    Until I found out that STM32CubeMX could generate LowLayer code. And I have to admit that I like that, it is simple, does just the initialization of the peripherals and nothing more. It is close enough to the hardware but (I think) it is more human readable, like this "LL_TIM_SetTriggerInput(TIM3, LL_TIM_TS_TI1FP1);" Of course you still have to have the Reference Manuals AND the Datasheets handy at all times.

    Unfortunately STM32CubeMX does not always generate complete initialization (at least in LowLayer mode). As an example, the settings for the RTC Calendar are completely ignored in the code it generates.

    I share your aversion against the examples, they are written in the most abscure way as far as I'm concerned. It also seems like they wanted to use just the Nucleo's / Discoveryboards and no other parts. Eg. see the I2C examples.

    I do the same as waclawek.jan does, write many small programs to test just one peripheral, and sometimes that still takes me days (not hours) I guess that's just the way it works.

    luch
    luchAuthor
    Associate II
    February 10, 2019

    Thanks Wilko!

    Yes, I agree with you about CubeMX generating LL code - it does not cover everything, but it's much more efficient than HAL.

    I'm trying the same approach as you and Jan - to write many simple programs and study every peripheral... Unfortunately, after more than a week on this, I am still at the setup stage: choosing the tools to use and creating a minimal program with the basic initialization of the micro. Then, knowing what set of instructions to use, to start experimenting. I'm slooooowly getting there!

    Willunen
    Associate III
    February 10, 2019

    Oh, the tools. For IDE software I started with Keil uVision but now it is Atollic TrueStudio combined with STM32CubeMX. The hardware is ST-Link-V2 and Segger J-Link EDU. And the controllers themselves, a mix of STM32F030, F100, F103, F407, L031 and L431 bought through Farnell or Ebay. I'm moving away from Ebay because of the fakes and recycled junk. But at this moment I'm still playing with a "blue pill" STM32F103. I have some Discovery and Nucleo boards but I don't like the Morpho- and Arduino pinout so I rarely use them.

    luch
    luchAuthor
    Associate II
    February 10, 2019

    I am using uVision - the limitations don't bother me at this point - mostly because the clear structure of the program and the debugger. I use a ST-Link-V2 for debbuging and have a few boards with F100, F103 and a L476. The little, cheap and widespread BluePill doesn't get much support from these tools - I found no example projects for it - speaking of bias...