Help to start with STM3L412 and libopenCM3 - Page 1
Forum section: electronics / general

author: psysc0rpi0n
author_rank: Frequent Contributor
timestamp: August 03, 2021, 11:53:50 am
content: Hello,So, I've been trying to grasp the basics of libopenCM3 libraries to use with my STM32L412CBT chip.DatasheetReference ManualFor now, I'm just trying to use a timer to blink a led. The initial stuff as usual.I was reading someone's post somewhere on the web about this and tried to replicate some of the steps.I can confirm with my scope that the following code is bringing the PIN I selected up.Code:rcc_periph_clock_enable(RCC_GPIOB);gpio_mode_setup(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO0);gpio_set_output_options(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_LOW, GPIO0);gpio_toggle(GPIOB, GPIO0);while(1){}Now, I started reading about timers and specific clock configuration within the source code of libopenCM3 itself, but it's quite a daunting task for someone with no experience with STM32 chips or libopenCM3, so I need some help to be able to understand how the clock blocks all work together and in isolated conditions and also to be able to use the correct libopenCM3 functions for each task.I want to use a basic timer (TIM6) which, according to the clock tree from the datasheet below, is affected by the following blocks in the way:And looking into the code of libopenCM3, I find this function to set the RCC PLL clock register:rcc_set_main_pll()Code:void rcc_set_main_pll (uint32_t source,uint32_t pllm,uint32_t plln,uint32_t pllp,uint32_t pllq,uint32_t pllr)But when I look in STM32CubeMX to help me with the dividers and multipliers, it tells me thatpllqis not available unless RNG or some IP mode is selected, so, I'm not sure what to send as parameter for this function.Similar question is forpllp. Reference manual says this is Main PLL division factor for PLLSAICLK (SAI1 clock). But a bit down in the reference manual, it's said that this PLLSAICLK isNot available on STM3L41xxx and STM32L42xxx devices.So, I'm a bit confused here.Even so, this is what I have for now, but I have no idea this is supposed to be like this and if it will work.Code:#include <libopencm3/stm32/gpio.h>#include <libopencm3/stm32/rcc.h>#include <libopencm3/stm32/timer.h>int main(void){rcc_set_msi_range(0xb0);rcc_set_main_pll(RCC_PLLCFGR_PLLSRC_MSI, // https://libopencm3.org/docs/latest/stm32l4/html/l4_2rcc_8h_source.html#l00272RCC_PLLCFGR_PLLM(1), // PLLM divider 1, RM0394, page 20140, // PLLN divider 40, RM0394, page 201, see also libopencm3 l4/rcc.h file, lines 252 to 255// STM32CubeMX says it's 40RCC_PLLCFGR_PLLP_DIV7, // verify this one, RM0394 page 200 and libopencm l4/rcc.h file, lines 246 to 250RCC_PLLCFGR_PLLQ_DIV2, // verify this one too. It's says in STM32CubeMX that it's not available, ony if IP or//RNG mode is selected. RM0394 page 200RCC_PLLCFGR_PLLR_DIV2); // PLLR divider 2, RM0394 page 200. STM32CubeMX says it's 2rcc_periph_clock_enable(RCC_GPIOB);gpio_mode_setup(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO0);gpio_set_output_options(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_LOW, GPIO0);gpio_toggle(GPIOB, GPIO0);while(1){}return 0;}So, if anyone is willing to dive a bit into this with me I would appreciate!

author: thm_w
author_rank: Super Contributor
timestamp: August 03, 2021, 09:55:20 pm
content: If its not available, should be fine to set it to 0.You can find some example code here:https://github.com/libopencm3/libopencm3-examples/blob/master/examples/stm32/l4/stm32l476g-disco/basics/basics.cpllcfg options:http://libopencm3.org/docs/latest/stm32g4/html/group__rcc__pllcfgr__values.htmlTo me it seems like you've got the right idea.

author: psysc0rpi0n
author_rank: Frequent Contributor
timestamp: August 04, 2021, 09:08:48 am
content: Quote from: thm_w on August 03, 2021, 09:55:20 pmI'm not sure I started in the right place. I want to use one of the internal clocks that allow me to have the 80Mhz for the timers clock. The image I posted above is from STM32CubeMX, but the one from the datasheet is slightly different.This is the one I should be sticking to:The difference is that in the image from my post above (STM32CubeMX), I assumed that the MSI input at the PLL Source Mux, was the block above it called MSI RC. Truth is that I'm not sure this is correct because in the datasheet, block diagram is a bit different.In STM32CubeMX, the block diagram shows a PLL Source Mux before the PLL block and in the dataseet, I can't see any mux before the PLL block.So, my question is if the MSI RC block in STM32CubeMX, marked in brown is the same from the one also marked in brown in the datasheet and if this is the input clock source that is feeding the PLL block and that later multiplies and divides to get the 80Mhz out, in the end! (don't mind the frequency and divider/multiplier values shown in the pictures).

author: Silenos
author_rank: Regular Contributor
timestamp: August 04, 2021, 09:38:23 am
content: I do not understand the red lines in your first pic from rm schematic. If my eyesight is correct, both cube and rm clock tree schematics are the same, and your color clouds in second pic are correct. And MSI connection point commented in red should be "connected before /M...", not "connected after /M...". You sure you haven't mistaken reading a direction of pre-pll mux?

author: psysc0rpi0n
author_rank: Frequent Contributor
timestamp: August 04, 2021, 09:53:31 am
content: Quote from: Silenos on August 04, 2021, 09:38:23 amThe red lines were just to show the path of the blocks that will be influenced by my final goal, which is to get 80Mhz at the end, using TIM6 and PLL.About the direction of pre-pll mux... I assume pre-pll mux is this:If so, I didn't notice the arrow pointing in (into) the PLL block. Does this means it is before the PLL block?Even so, in STM3CubeMX, this PLLM parameter isexiting(after) the PLL block.Edited;Ignore, I see now that my mind was kinda blocked/stuck making me see that PLLM parameter was exiting PLL block when it is in fact exiting the PLL source mux (which I think you called pre-pll mux)

author: Silenos
author_rank: Regular Contributor
timestamp: August 04, 2021, 10:23:23 am
content: The "/M" and "PLLM" labels are the same thing.

author: psysc0rpi0n
author_rank: Frequent Contributor
timestamp: August 04, 2021, 11:29:25 am
content: Quote from: Silenos on August 04, 2021, 10:23:23 amYes, that one is obvious.What I was making confusion with was with PLL Source Mux (STM32CubeMX) and the PLL block itself.Ok, I think I got this part.Now I'm searching libopencm3 source code where we set the AHB and APB1 prescaler values. I mean, what are the functions we should use to set these values.

author: Kjelt
author_rank: Super Contributor
timestamp: August 04, 2021, 11:40:09 am
content: I would really advise this book, it will help you get up and running quickly with low frustration levels.

author: psysc0rpi0n
author_rank: Frequent Contributor
timestamp: August 04, 2021, 01:27:10 pm
content: I still couldn't find where we set AHB and APB1 prescaler values in libopencm3 library source code.I can see all these functions:I can see all these subject in reference manual but none is to set prescalers, as far as I knowAny hint?

author: psysc0rpi0n
author_rank: Frequent Contributor
timestamp: August 04, 2021, 01:34:49 pm
content: Quote from: Kjelt on August 04, 2021, 11:40:09 amI also searched in that book, but the functions used there are deprecated or no longer available:In page 280 an 281 is described a list of SYSCLK dividersand ana example:but this function is no longer used, it's deprecated:Then, I search for the suggested replacement function but I can't find one for "l4" series:So, I'm sitll not sure how to set AHB and APB1 presclers.

author: Kjelt
author_rank: Super Contributor
timestamp: August 04, 2021, 02:44:42 pm
content: They changed it then. Has been a while ago since I last used libopen and that was with a F4 not an L4.Strange. Can not find much on their wiki or site.Check rcc.h and compare it to an older version see what interface functions changed.

author: Kjelt
author_rank: Super Contributor
timestamp: August 04, 2021, 03:18:32 pm
content: Ah ok found that this function is still there but only in the STM32F1 directory in the rcc.c file.For the newer uCs they have deprecated it. You have to call the functions your self, but you can still see the example in the F1 directory, looks like the same rcc_ functions are available for L4.So you have to find a simple blinky example for F4 or L4 then, probably just as easy but a couple of more function calls.

author: psysc0rpi0n
author_rank: Frequent Contributor
timestamp: August 04, 2021, 05:30:17 pm
content: Quote from: Kjelt on August 04, 2021, 03:18:32 pmI found an example at some site and I'm making a few changes. I have to select another timer, because TIM6 doesn't have an Output Comparator pin and I need a timer that has this feature to be able to follow the example. This example also uses functions from libopenCM3, so, at least it gives me hints on the functions to use.For reference:https://bdebyl.net/post/stm32-part1/

author: psysc0rpi0n
author_rank: Frequent Contributor
timestamp: August 04, 2021, 06:52:37 pm
content: Ok, this is what I have for now:Code:#include <libopencm3/stm32/gpio.h>#include <libopencm3/stm32/rcc.h>#include <libopencm3/stm32/timer.h>int main(void){rcc_set_main_pll(RCC_PLLCFGR_PLLSRC_MSI, // Clock source MSI RC// libopencm3 l4/rcc.h, line 272// RM0394, page 201RCC_PLLCFGR_PLLM(1), // PLLM divider 1// libopencm3 l4/rcc.h, line 266// RM0394, page 201// STM32CubeMX says it's 1// RM says PLLSAI1 is not available for STM32L41280, // PLLN divider 80// libopencm3 l4/rcc.h file, lines 252 to 255// RM0394, page 201// STM32CubeMX says it's 80 for the default MSI RC clock of 4MhzRCC_PLLCFGR_PLLP_DIV7,// libopencm3 l4/rcc.h file, lines 246 to 250// RM0394 page 200// Doesen't matter for STM32L412. PLLSAI1 is not availableRCC_PLLCFGR_PLLQ_DIV2,// libopencm3 l4/rcc.h file, line 240,// RM0394 page 200// Disabled for this case.RCC_PLLCFGR_PLLR_DIV4); // PLLR divider 4// libopencm3 l4/rcc.h// RM0394 page 200// STM32CubeMX says it's 4 for the default MSI RC clock of 4Mhzrcc_set_ppre1(RCC_CFGR_PPRE1_NODIV); // APB1 prescaler to 1 (no div)rcc_set_hpre(RCC_CFGR_HPRE_NODIV); // AHB prescaler to 1 (no div)rcc_periph_clock_enable(RCC_GPIOA);timer_set_mode(TIM2, TIM_CR1_CKD_CK_INT,TIM_CR1_CMS_EDGE,TIM_CR1_DIR_UP);gpio_mode_setup(GPIOA, GPIO_MODE_AF,GPIO_PUPD_NONE, GPIO10);gpio_set_output_options(GPIOA, GPIO_OTYPE_PP,GPIO_OSPEED_HIGH, GPIO10);gpio_set_af(GPIOA, GPIO_AF1, GPIO10);timer_set_prescaler(TIM2, (rcc_apb1_frequency/80000)/2*1); < -------- NOT SURE HOW THIS WORKS HEREtimer_set_period(TIM2, 80000);timer_disable_preload(TIM2);timer_continuous_mode(TIM2);rcc_periph_clock_enable(RCC_GPIOA);gpio_mode_setup(GPIOA, GPIO_MODE_AF,GPIO_PUPD_NONE, GPIO10);timer_set_mode(TIM2, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE,TIM_CR1_DIR_UP);gpio_toggle(GPIOA, GPIO10);while(1){}return 0;}I'm not sure how the prescaler value works. Apparently this is where you put the upper limit of our counter. So, in the example I'm following, is said that:QuoteAnd they use the following code:Code:rcc_clock_setup_in_hsi_out_48mhz(); // Place at the beginning of your int 'main(void)'...// SECONDS: integer value of period (seconds) of LED blinktimer_set_prescaler(TIM3, (rcc_apb1_frequency/48000)/2*SECONDS));In my case, I set AHB and APB1 frequencies to 80Mhz. So, How am I going to compute, let's say, 300 miliseconds for a led to blink?

author: thm_w
author_rank: Super Contributor
timestamp: August 04, 2021, 08:51:11 pm
content: Quote from: psysc0rpi0n on August 04, 2021, 06:52:37 pmProbably an english language thing. Prescaler = scale the clock, so divide it down. Its not an upper limit, that would be related to the preload or max register value.So if the timer is 80MHz, then prescale is set to 10, now the timer will run at 8MHz.Assuming 16-bit timer, max prescale is probably 65536. So prescale by whatever makes sense to you, since you need low timer resolution, maybe 10000 or 40000.

author: psysc0rpi0n
author_rank: Frequent Contributor
timestamp: August 05, 2021, 08:47:39 am
content: Quote from: thm_w on August 04, 2021, 08:51:11 pmI know what the prescaler is meant to do. What I'm not sure about is how it relates to the value I want/need the led to blink.You say the if the timer is 80Mhz, thhen prescale is set to 10. How do you know this?

author: Kjelt
author_rank: Super Contributor
timestamp: August 05, 2021, 09:25:00 am
content: Quote from: psysc0rpi0n on August 04, 2021, 06:52:37 pmThis depends what you exactly want since there are many solutions for this.Lets start with how I look at it, but as said many things are possible.Look at the reference manual of your uC and esp. on the timer chapter and look at the time base unit and upcounting mode.So to do this you need to have the clock activated to your timer, you need to know the frequency.Then you calculate how much to divide the clock signal to get the wanted frequency.That division you split between the prescaler and the upcounting register ARR.So for instance you have a 80MHz clock to the timer and you want the ARR to overflow after 300ms (3.3Hz)Then you need to divide the 80MHz clock by 24242424. The max value of the prescaler is 65535 you are left with 1220 Hz.To divide the 1220Hz to 3.3Hz again a factor of 360 is needed. So that is the value of the ARR register.Now you still have to do some things. First enable the timer (start timer) and enable the interrupts of that timer register and map the overflow interrupt to your interrupt handler.In that interrupt handler you toggle the led. Measure with an oscilloscope the exact frequency and correct with the ARR value. If you can not get it perfect you need a multi step plan.So personally I find it a waste to set a hardware timer peripheral to those low speeds.What I usually do is use one generic HW timer to generate for instance a 1ms interrupt, and in that 1ms interrupt handler I update the software timer module (a piece of software with different user configurable timers 8bit, 16 bit etc) that are increased or decreased by the 1ms interrupt handler.In your code you have a superloop or RTOS and there you check if the software counter has expired (with downcounting software timers) if so you toggle the led.But I don't want to make it more difficult than it is.If you do not succeed with the above, then you can do some fast checks: in your code readout the ARR register and display or store it and view it, it should increase to 360 then start over at 0.If you do not see the ARR increasing, check if you have started the timer (enabled it) , still does not work, set the frequency lower. Change the 80MHz to 16MHz or so and try again.

author: thm_w
author_rank: Super Contributor
timestamp: August 05, 2021, 09:00:42 pm
content: Quote from: psysc0rpi0n on August 05, 2021, 08:47:39 amIts just an example, you set prescaler to any number between 1 and 65535 in your code.Thats why I said you could set it to 10,000 or 40,000 as well.

author: psysc0rpi0n
author_rank: Frequent Contributor
timestamp: August 05, 2021, 11:36:23 pm
content: Quote from: Kjelt on August 05, 2021, 09:25:00 amOk, I think I did that here:Code:timer_set_mode(TIM2, TIM_CR1_CKD_CK_INT,TIM_CR1_CMS_EDGE,TIM_CR1_DIR_UP);TIM_CR1_DIR_UPis for upcounting.About base unit, the reference manual says:QuoteI'm not sure how to interpret this and what to retain for what I need.Quote from: Kjelt on August 05, 2021, 09:25:00 amIf I did things correctly, the Timer frequency is 80Mhz.I activate the clock here:rcc_periph_clock_enable(RCC_TIM2);Quote from: Kjelt on August 05, 2021, 09:25:00 amOk, just to confirm I got it, the procedure is to divide the timer clock frequency by the time we want our led on. As we can't mix up frequency with time, we convert the time to frequency. That's 1/300ms = 3.3Hz.So, 80Mhz / 3.3Hz is that 24242424 value that would be the one to set in ARR but it can only take up to 65536, so we need to go back and divide again the 80Mhz by 65536 and we get 1220Hz, approximately.In practice, correct me if I'm wrong, it will take 300ms for the timer to overflow at a frequency of 1220Hz, yes?And in terms of code, as I was following the other example I found, I probably did this wrong.The other example used thercc_apb1_frequencyconstant (which is 4Mhz) to calculate the value for the prescaler, and to be honest, I'm a bit lost here.timer_set_prescaler(TIM2, (rcc_apb1_frequency/80000)/2*1);Instead of that value, I want there the 1220, right?Quote from: Kjelt on August 05, 2021, 09:25:00 amI enabled the timer here:timer_enable_counter(TIM2);but I didn't do the interrupt thing. I thought that wouldn't be needed because, at least I thought, I was using the Output Compare Mode. Quoting the reference manual:QuoteI think I setup the timer accordingly here:timer_set_oc_mode(TIM2, TIM_OC1, TIM_OCM_PWM1);But I also got a bit confused here when I was reading the example, because the Output Compare Mode was selected but then there is thatTIM_OCM_PWM1constant/macro that made me think if we are on Output Compare Mode or in some PMW mode.Quote from: Kjelt on August 05, 2021, 09:25:00 amWell, I don't want and I can't discuss other solutions because I'm just learning. I'm sure that in a production environment, that would probably be faster, more efficient and less time consuming. As of my situation, I started this as a learning process, so I want to get familiar with the most common libopencm3 functions that setup these most common peripherals, clocks, etc and maybe later I can think about alternatives, when I'm more comfortable.Quote from: Kjelt on August 05, 2021, 09:25:00 amYes, as of now, I want to make it as simple and straight forward as possible, taking into account that I want to learn more about libopencm3 and the stm32 chips themselves.

author: abyrvalg
author_rank: Frequent Contributor
timestamp: August 06, 2021, 06:07:06 am
content: Note that PA10 pin you are configuring is timer channel3, so you need to configureTIM_OC3, not 1.

author: psysc0rpi0n
author_rank: Frequent Contributor
timestamp: August 06, 2021, 07:36:39 am
content: Quote from: abyrvalg on August 06, 2021, 06:07:06 amMy datasheet says otherwise:TIM2_CH1Am I right, right?

author: Kjelt
author_rank: Super Contributor
timestamp: August 06, 2021, 08:26:13 am
content: Quote from: psysc0rpi0n on August 06, 2021, 07:36:39 amNo you are looking at the physical ic device pin, you should be looking at the logical pin function name, see picture. So abyrvalg is right, PA10 is tim3 and PA0 is tim2.

author: Kjelt
author_rank: Super Contributor
timestamp: August 06, 2021, 08:34:28 am
content: So on your previous post, yes if you use the timer as capture/compare and toggle the output that should work.Unfortunately I am full time at work again and do not have the libopen environment and other hw to "play along" as Dave always eloquently puts it, so hopefully some student or retired forum member might help you further.To correct a mistake I made in a previous post, the counter register is the register you can read out if you want to check if the timer is running, it should increase each time you read it out till it overflows.But if you set the capture compare mode to a value than it will overflow sooner. You do have some debug (usb or serial) output so you can see what you are doing ? Good luck.

author: psysc0rpi0n
author_rank: Frequent Contributor
timestamp: August 06, 2021, 08:46:58 am
content: @kjeltOh I see. Ok, my goal is to use TIM2_CH1, so I already changed the code to reflect this (fixed) mistake.GPIO10toGPIO0So, now I have:Code:gpio_mode_setup(GPIOA, GPIO_MODE_AF,GPIO_PUPD_NONE, GPIO0);gpio_set_output_options(GPIOA, GPIO_OTYPE_PP,GPIO_OSPEED_HIGH, GPIO0);gpio_set_af(GPIOA, GPIO_AF1, GPIO0);I am using OpenOCD, GDB and a J-Link clone. I'm not even going to detail now some other weird things that have been happening to me with this J-Link. Maybe later.Edited:And I can see now that my physical pin 10 goes high at this line of code:Code:timer_enable_oc_output(TIM2, TIM_OC1);But then, stays high for ever, so I think I have the period and prescaler and comparator value wrong.

author: Kjelt
author_rank: Super Contributor
timestamp: August 06, 2021, 09:14:16 am
content: I can advise you to use an oscilloscope on the pin to see what's going on since >200Hz you won't be able to see it.If you don't have an oscilloscope, start using a lower system clock, 80MHz is pretty high for the first experiments, first set it to say 16MHz or 24MHz and increase the timer prescaler till you have a lower frequency.Also double check if you set the timer to toggle the output (or can toggle (OCxM=011) on match.

author: psysc0rpi0n
author_rank: Frequent Contributor
timestamp: August 06, 2021, 09:49:37 am
content: Quote from: Kjelt on August 06, 2021, 09:14:16 amI have a scope and that's how I saw my physical pin 10 (PA0) went high!I just need some more help to understand how to setup period and compare value. I think that's what is missing now!

author: abyrvalg
author_rank: Frequent Contributor
timestamp: August 07, 2021, 07:00:07 am
content: Have you also set the OC compare value to nonzero? Otherwise you’ll get "0% duty cycle" in PWM1 mode. Or change the OC mode to TIM_OCM_TOGGLE - this should toggle the pin each full count cycle regardless of the OC value (it will control the phase now) if I understand it correctly.

author: psysc0rpi0n
author_rank: Frequent Contributor
timestamp: December 12, 2021, 04:02:55 pm
content: I eventually got back to this. I've been busy with other things, and also, to be honest, I lost some interest because I couldn't make this work.Anyway, I'm always questioning my setup because it sometimes behaves differently under the same conditions.In my case, I have a Jlink clone (v9,link) connected between my laptop and my bare chip which I soldered onto a small LQFP48 PCB converter likethis.I'm using an external power supply to feed the chip with 3.32v.Being my Jlink pin 1 the Vtref pin, should this pin have any voltage when floating? If I am not mistaken, this pin must be connected to my chip Vcc, which is where I connect my external power supply 3.3V, right? I'm always confused with this pin.As I said in the beginning of this thread, I'm using openocd an gdb to load, run and test the code. However, somehow, I think this Vtref pin is feeding the circuit. I say this because if I disconnect the power supply, I can still load the code, run it, etc, as if the external power supply was connected. And I have no idea how normal this is or if it should be happening at all.These are 2 images of my jlink deviceThere is this jumper inside my device that I think is to put 3.3V on pin 2 if needed. Other than that, I have no idea of another use.But with these said, I can't even trust in my setup. I mean, be able to load and run code with the external power supply disconnected is very weird.However, I tried a very simple code to set and clear a pin, and I could catch both events on scope, so, I must say it is working!

author: thm_w
author_rank: Super Contributor
timestamp: December 14, 2021, 10:37:46 pm
content: Quote from: psysc0rpi0n on December 12, 2021, 04:02:55 pmThe cheap jlink clones will send 3.3V onto Vtref and power the target. Some will have a switch to select 1.8 or 3.3V. You'll have to figure out what your switch does, my guess is it will connect/disconnect 3.3V from Vtref.If you need to power it externally, may be better to leave Vtref disconnected.This is more convenient than the official Jlink, which does not power Vtref, but has a switched power output on another pin of 5V. But, worse if you want to switch power off and on (to reset other peripherals) or not supply it..

author: psysc0rpi0n
author_rank: Frequent Contributor
timestamp: December 15, 2021, 11:46:57 pm
content: Quote from: thm_w on December 14, 2021, 10:37:46 pmWhat these 3 pins do, when I change the jumper from one side to the other is that pin 2 gets 3.3v or NC... Nothing happens on the Vtref pin.Anyway, I tried to setup the clocks again, to get 80Mhz but I must be missing something and I can't figure out what is it.This is the code I have so far:Code:#include <libopencm3/stm32/gpio.h>#include <libopencm3/stm32/rcc.h>#include <libopencm3/stm32/timer.h>int main(void){rcc_set_msi_range(RCC_CR_MSIRANGE_4MHZ);rcc_set_pll_source(RCC_PLLCFGR_PLLSRC_MSI);rcc_set_main_pll(RCC_CFGR_SW_PLL,RCC_PLLCFGR_PLLM(1),40, // PLLN x40RCC_PLLCFGR_PLLP_DIV7, // PLLP ??? Not sureRCC_PLLCFGR_PLLQ_DIV2, // doesn't matterRCC_PLLCFGR_PLLR_DIV2);rcc_set_hpre(RCC_CFGR_HPRE_NODIV); // Set AHB prescalerrcc_set_ppre1(RCC_CFGR_PPRE1_NODIV); // Set APB1 prescalerrcc_set_ppre2(RCC_CFGR_PPRE2_NODIV); // Set APB2 prescalerrcc_set_sysclk_source(RCC_CFGR_SW_PLL);rcc_pll_output_enable(RCC_PLLCFGR_PLLREN);rcc_periph_clock_enable(RCC_GPIOA);gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO10);gpio_set_output_options(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_LOW, GPIO10);gpio_set_af(GPIOA, GPIO_AF1, GPIO10);/* enable clock and configure the timer */rcc_periph_clock_enable(RCC_TIM1);timer_set_mode(TIM1, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);timer_continuous_mode(TIM1);timer_direction_up(TIM1);timer_enable_preload(TIM1);timer_enable_break_main_output(TIM1);/* counting at 1 MHz */timer_set_prescaler(TIM1, 3);/* overflowing at 1 kHz */timer_set_period(TIM1, 999);timer_enable_oc_preload(TIM1, TIM_OC3);timer_set_oc_mode(TIM1, TIM_OC3, TIM_OCM_PWM1);/* 1/4 duty cycle */timer_set_oc_value(TIM1, TIM_OC3, 499);/* enable the timer and PWM output */timer_enable_oc_output(TIM1, TIM_OC3);timer_enable_counter(TIM1);while(1);}The result on the scope is that if I was still using default clocks. Can anyone help me figuring out what am I doing wrong?

author: emece67
author_rank: Frequent Contributor
timestamp: December 16, 2021, 10:22:17 am
content: .

author: hansd
author_rank: Contributor
timestamp: December 16, 2021, 12:47:52 pm
content: Hi,Attached is some basic code using OLIMEX STM32-H405 blinking an led. The code should give you some understanding how to use the library and get the mcu to run and end up in main. I did rip apart the library to see what I really need to startup the micro and use the system timer.There is also a book called Beginning STM32: Developing with FreeRTOS, libopencm3 and GCC.Hope this helps.

author: julian1
author_rank: Frequent Contributor
timestamp: December 16, 2021, 08:59:59 pm
content: QuoteIt is not clear from reading the last few posts. Do you have the full complement of decoupling and vcap in place? Does the stm32 answer on openocd when you connect up the debugger? Can you do a 'reset halt', and 'reset run' .The more common way to do blinky - to demonstrate and confirm the toolchain works end-to-end (openocd, st-link, code, and board hardware), is to just wiggle the gpio in a for loop. There's no reason to setup hsi, and peripheral timer.

author: psysc0rpi0n
author_rank: Frequent Contributor
timestamp: December 16, 2021, 09:43:01 pm
content: @emece67 I have just took a look to your examples.Doing things that way is maybe for people feeling quite comfortable with STM32 chips, libopencm3, etc. I did with AtMega328 some time ago, but STM32 are an whole other level and I'm not experienced or anything like that to be able to do things almost register by register!I started by reading a few examples I found in the internet and trying to go through libopencm3 doxygen docs.The benefit of using such functions, IMHO, is just a matter of user-friendly names that help the beginner to know what is happening with that function. But the point is that if it works, then it's ok. Some say that "good enough, is perfect".Anyway, I see you power up a bunch of registers and you also change some backup registers. I am not doing any of that. I assume that those settings are not critical to get the chip up and running as I saw examples that either they don't do any of that or the functions used already do it implicitly.From the steps you mention, I can identify most of them and I think I take care of those in my code too. However, there are some steps I'm not sure they are what I think, probably because I'm not used to the terminology. Another detail I noticed is that you take care explicitly of waiting times until registers are ready. I'm not even sure if libopencm3 code is taking that into account, because many of the functions don't have wait cycles. So, this one leaves me wondering!@hansd I also took a look to your code. I see you use a complete different set of functions to get your setup up and running. My problem is that I'm just starting with STM32 and there are many details unknown to me and even reading the datasheet and reference manual, I still have many beginner questions. I searched libopencm3 code for some of the functions you used but I didn't dig deep into them because I want to try to stick to my code until I figure out what is wrong with it! I think I'm pretty close and this is probably a tiny thing that is stopping me from moving on. I hope to get it figured out as quickly as possible, so that I can move on!@julian, I can't say I have a "by-the-book" set of decoupling capacitors. I have the chip on an LQFP48 converter chip and then I have a couple of wires to a breadboard Vcc and Gnd lines, where I have a few decoupling capacitors to filter out undesired noise. Then I have my external power supply connected to the same Vcc and Gnd lines of the breadboard. The Jlink device is connected directly to the chip but the Vcc and Gnd lines which are also conencted to the breadboard Vcc and Gnd lines.Yes, chip answers to openocd, to gdb and I can load the code, I can run it, debug it, etc. If I use the default clocks, I can get the expected result on my scope! So, the setup is fine!Edited;I changed a couple of things in my code but it is still not working as expected. This is how it looks now:Code:#include <libopencm3/stm32/gpio.h>#include <libopencm3/stm32/rcc.h>#include <libopencm3/stm32/timer.h>int main(void){rcc_set_msi_range(RCC_CR_MSIRANGE_4MHZ);//rcc_set_pll_source(RCC_PLLCFGR_PLLSRC_MSI);rcc_set_main_pll(RCC_PLLCFGR_PLLSRC_MSI,RCC_PLLCFGR_PLLM(1),40, // PLLN x40RCC_PLLCFGR_PLLP_DIV7, // PLLP ??? Not sureRCC_PLLCFGR_PLLQ_DIV2, // doesn't matterRCC_PLLCFGR_PLLR_DIV2);rcc_set_hpre(RCC_CFGR_HPRE_NODIV); // Set AHB prescalerrcc_set_ppre1(RCC_CFGR_PPRE1_NODIV); // Set APB1 prescalerrcc_set_ppre2(RCC_CFGR_PPRE2_NODIV); // Set APB2 prescalerrcc_set_sysclk_source(RCC_CFGR_SW_PLL);rcc_pll_output_enable(RCC_PLLCFGR_PLLREN);rcc_osc_on(RCC_MSI);rcc_periph_clock_enable(RCC_GPIOA);gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO10);gpio_set_output_options(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_LOW, GPIO10);gpio_set_af(GPIOA, GPIO_AF1, GPIO10);/* enable clock and configure the timer */rcc_periph_clock_enable(RCC_TIM1);timer_set_mode(TIM1, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);timer_continuous_mode(TIM1);timer_direction_up(TIM1);timer_enable_preload(TIM1);timer_enable_break_main_output(TIM1);/* counting at 1 MHz */timer_set_prescaler(TIM1, 3);/* overflowing at 1 kHz */timer_set_period(TIM1, 999);timer_enable_oc_preload(TIM1, TIM_OC3);timer_set_oc_mode(TIM1, TIM_OC3, TIM_OCM_PWM1);/* 1/4 duty cycle */timer_set_oc_value(TIM1, TIM_OC3, 499);/* enable the timer and PWM output */timer_enable_oc_output(TIM1, TIM_OC3);timer_enable_counter(TIM1);while(1);}

author: psysc0rpi0n
author_rank: Frequent Contributor
timestamp: February 20, 2022, 12:05:43 pm
content: Well, after fighting against this for months (quitting and resuming), I think I finally got it working.In the process I also discovered a broken GND leg of my scope which made things a bit harder than what they already were.Anyway, my scope, despite it is a 100Mhz Rigol MSO1104Z, seems to not be able to keep up in terms of showing correct wave forms on higher frequencies. 80Mhz, simply shows a sine wave. At 40Mhz, there is some resemblance to a square wave but still very distorted. At lower frequencies, I'm still not proud of the scope, but it is what it is. Even at 10Mhz, the rise and fall edges are curvy and there is some ringing even with a 100 ohm resistor serving as load at the pin where I'm outputting the signal.Thhe code to make it work is this:Code:#include <libopencm3/stm32/rcc.h>#include <libopencm3/stm32/gpio.h>#include <libopencm3/cm3/nvic.h>#include <libopencm3/cm3/systick.h>#include <libopencm3/stm32/flash.h>static void clock_setup(void){/* set, enable and wait for MSI clock */rcc_osc_on(RCC_MSI);rcc_wait_for_osc_ready(RCC_MSI);rcc_set_msi_range(RCC_CR_MSIRANGE_16MHZ);flash_prefetch_enable();flash_set_ws(4);flash_dcache_enable();flash_icache_enable();/* set, enable and wait for main PLL *//*MSI = 4Mhz, M = 1,* N = 40,* P = DIV7 = 0,* Q = DIV2 = 0,* R = DIV2 = 2*/rcc_set_main_pll(RCC_PLLCFGR_PLLSRC_MSI,4,//RCC_PLLCFGR_PLLM(1),20,RCC_PLLCFGR_PLLP_DIV7,RCC_PLLCFGR_PLLQ_DIV2,RCC_PLLCFGR_PLLR_DIV8);rcc_osc_on(RCC_PLL);rcc_wait_for_osc_ready(RCC_PLL);/* set, enable and wait for Sys Clk */rcc_periph_clock_enable(RCC_SYSCFG);rcc_set_sysclk_source(RCC_CFGR_SW_PLL);rcc_wait_for_sysclk_status(RCC_PLL);//Enable clocks to the GPIO subsystemsrcc_periph_clock_enable(RCC_GPIOA);}static void mco_setup(void){/* PA8 to AF 0 for MCO *///rcc_periph_clock_enable(RCC_GPIOA);gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO8);gpio_set_af(GPIOA, 0, GPIO8);gpio_set_output_options(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, GPIO8);/* clock output on pin PA8 (allows checking with scope) */rcc_set_mco(RCC_CFGR_MCO_SYSCLK);}int main(void){clock_setup();//gpio_setup();mco_setup();/* Do nothing in main loop */while (1);}

author: 2N3055
author_rank: Super Contributor
timestamp: February 20, 2022, 08:10:27 pm
content: Quote from: psysc0rpi0n on February 20, 2022, 12:05:43 pmYour scope is doing it's work perfectly and what you see is normal.100Mhz scope means it can showsinusoidal100Mhz signal with 3dB attenuation.Squarewave signal that is 80Mhz will have large frequency components at 240MHz, 400Mhz, 560Mhz.Since you didn't buy 500Mhz scope but 100Mhz one you see only 80Mhz sinewave part of it.. Simple as that.Combine that with passive scope probes that have large capacitive loading on your signal, and long ground wire on the probe (that will create ringing).Do you use probe in 1x or 10X setting?What exact risetimes do you measure ??

author: psysc0rpi0n
author_rank: Frequent Contributor
timestamp: February 21, 2022, 04:23:55 pm
content: Quote from: 2N3055 on February 20, 2022, 08:10:27 pmI'll post some pictures here.https://i.ibb.co/RNnJm0g/DS1-Z-Quick-Print20.pnghttps://i.ibb.co/0XccQ1K/DS1-Z-Quick-Print21.pngThe thing is that at way lower frequencies, that are not even multiples of 80Mhz (chip signal) nor 100Mhz (scope bandwidth), 12Mhz in this case of the other picture, I still can't see a very accurate square wave. I mean, it's way better but still far from a sharp square wave.I am using a "dummy" load resistor of 100 ohm at the same point where I have the scope probe to help avoid ringing, but still we see some!

author: 2N3055
author_rank: Super Contributor
timestamp: February 21, 2022, 04:36:01 pm
content: Quote from: psysc0rpi0n on February 21, 2022, 04:23:55 pmAgain, what probe are you using and how ?100Ohm at source doesn't matter if your probe is ringing...100Ohm in parallel or in series with probe?Lose resistor and connect probe without grounding wire and by using tip grounding spring..Also signal coming out of MCU pin will not look like a perfect square either. It will have ground bounce by itself, depending on how well power distribution is done on the board.

author: psysc0rpi0n
author_rank: Frequent Contributor
timestamp: February 21, 2022, 06:22:57 pm
content: The probe is the original probe from my Rigol MSO1104Z. It's an RP2200.the resistor is in series with the mcu pin, and in parallel with the probe.mcu pin ---------- 100Ohm --- GND| |scope probe |------------------|- GNDSomething like this.I'm not sure what you mean by "tip grounding spring". Can you please tell me that by other words?I'm using the bare chip in a small board like this:https://azsiacenter.com/278955-thickbox_default/2db-qfp-tqfp-fqfp-lqfp-32-44-64-80-100-dip-adapter-edelbrock-atalakito.jpg

author: 2N3055
author_rank: Super Contributor
timestamp: February 21, 2022, 07:41:11 pm
content: Quote from: psysc0rpi0n on February 21, 2022, 06:22:57 pm100 Ohms is very low load for a MCU GPIO pin. To measure signal you don't need it at all. Pin can be enabled as open source or push-pull,From datasheet:......Output driving currentThe GPIOs (general purpose input/outputs) can sink or source up to ±8 mA, and sink orsource up to ± 20 mA (with a relaxed VOL/VOH).3.3V with 100Ohm resistor violates that, 50% for high current mode , and order of magnitude for normal mode.Configure pin in push-pull driving mode and no resistor is needed.Probe:There is series of articles here. Read them all. Take few hours. It will save you lifetime of grief...:https://teledynelecroy.com/doc/passive-probe-ground-lead-effectsSome practical tips:https://www.eevblog.com/forum/beginners/diy-oscilloscope-probe-ground-spring/Hope that helps..

author: psysc0rpi0n
author_rank: Frequent Contributor
timestamp: February 22, 2022, 04:23:49 pm
content: Quote from: 2N3055 on February 21, 2022, 07:41:11 pmOk, I tried to remove the 100 Ohm resistor, measure at the MCU pin with the pin configured as PULLUP. This is what I get for 80Mhz and 10Mhzhttps://i.ibb.co/P5Xb70Y/DS1-Z-Quick-Print22.pnghttps://i.ibb.co/rm6Dm6D/DS1-Z-Quick-Print23.pngI also change the drive strength of the pin according to the frequency in questionFor 80Mhz I used:Code:gpio_set_output_options(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_100MHZ, GPIO8);For 10Mhz I used:Code:gpio_set_output_options(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, GPIO8);Edited:I also tried PULLDOWNhttps://i.ibb.co/HGTNT9f/DS1-Z-Quick-Print24.png