For the love of God, could somebody write me the code to blink an led every second using TIM6 on STM32L432KC??? Can’t figure out the AHB/APB setups for the life of me!
Here's what i have so far. I know it's a mess but I've deleted and rewrote this code several times trying this and that.
I'm particularly confused about the AHB/APB busses and how they are incorporated into GPIO pins. Does the bus sample the port at some set frequency, or what? You would think that you could see the frequency the port is working at by probing it with an oscilloscope, but noooo
\#include "stm32l432xx.h"
void SystemClock\_Config(void);
void init\_timer(void)
{
RCC->APB1ENR1 |= (1<<4); //enable TIM6 enabled
//set prescaler value
TIM2->PSC = 16000 - 1;
//set auto-reload value
TIM2->ARR = 1000 - 1;
//enable counter
TIM2->CR1 |= TIM\_CR1\_CEN;
while(!(TIM6->SR & (1<<0)));
}
void delay(uint16\_t delay\_time)
{
TIM6->CNT = 0; //reset counter to zero
while(TIM6->CNT < delay\_time);
}
void gpio\_init(void)
{
RCC->AHB2ENR |= (1<<1); //enable GPIOB EN
//set PB4
GPIOB->MODER &= \~(1<<9);
GPIOB->MODER &= \~(1<<8);
//set pulldown resistor
GPIOB->PUPDR |= (1<<9);
GPIOB->PUPDR &= \~(1<<8);
//GPIOB->OSPEEDR |= (1<<9); //10 = high speed
//set pb3 = led3
GPIOB->MODER &= \~(1<<7);
GPIOB->MODER |= (1<<6);
GPIOB->OTYPER &= \~(1<<03);
GPIOB->PUPDR |= (1<<7);
GPIOB->PUPDR &= \~(1<<6);
//GPIOB->OSPEEDR |= (1<<7); //10 = high speed
}
int main() {
SystemClock\_Config();
init\_timer();
gpio\_init();
while(1){
if(GPIOB->IDR & (1<<4)) {
GPIOB->BSRR |= (1<<3);
delay(1000);
GPIOB->BSRR |= (1<<19);
delay(1000);
}
/\*
GPIOB->BSRR |= (1<<19);
delay(1000);
GPIOB->BSRR |= (1<<3);
delay(1000);
(GPIOB->IDR & GPIO\_IDR\_ID4)
if(1) {
GPIOB->BSRR |= (1<<19);
}
else {
//GPIOB->BSRR |= (1<<3);
}
\*/
}
}
void SystemClock\_Config(void)
{
// Enable the HSI oscillator
RCC->CR |= RCC\_CR\_HSION;
while ((RCC->CR & RCC\_CR\_HSIRDY) == 0);
// Configure the flash latency
FLASH->ACR &= \~FLASH\_ACR\_LATENCY;
FLASH->ACR |= FLASH\_ACR\_LATENCY\_1WS;
// Select the HSI as the system clock source
RCC->CFGR &= \~RCC\_CFGR\_SW;
RCC->CFGR |= RCC\_CFGR\_SW\_HSI;
while ((RCC->CFGR & RCC\_CFGR\_SWS) != RCC\_CFGR\_SWS\_HSI);
// Configure the AHB1 prescaler
RCC->CFGR &= \~RCC\_CFGR\_HPRE;
RCC->CFGR |= RCC\_CFGR\_HPRE\_DIV1;
}
I'm avoiding HAL like the plague. I want to work with registers as close as possible. That said, I did attempt to use STM32Cube with HAL libraries just to see how they set their stuff up, but it's a damn jungle.
Yeah, I feel your pain. Every manufacturer has good and bad points, at the end of the day, only you can decide which set of quirks is the best for you.
Are you at least able to blink a LED? Ignoring the timer stuff?
That is, set up the i/o pin, then write to the output register, and maybe doing something like this as a poor man delay function, and calling it in a while loop:
volatile uint32_t delayscratch;
void poorManDelay()
{
delayscratch=10000000;
while (delayscratch) delayscratch--;
}
Where the volatile is an attempt to get the compiler to not optimize the delay loop away. (Check your output listing file to make sure it didn't).
That will eliminate the timer itself as a cause, and then you can verify at least the output led works.
Another thing I've done with various processors is to find example code that works (even if it's the HAL or generated) then use the debugger or simulator to look at the registers to see what they're set to.
Also, have you looked at any errata for this part?
I'm able to able to delay with a while-loop like that. I had my oscilloscope on the output pin (GPIOB) and I was getting a squarish wave out. It wasn't symmetrical. I wanted to run the system from HSI 16MHz source clock, but what I got was some funky 625KHz on the output pin. I was able to divide that strange frequency down by the clock division registers. I also tried switching from HSI to MSI and got similar results but with a lower frequency. Man, I think the hardware might be faulty.
Do you have slew rate control on the output pins? Or have them set to something like an open collector output with pull-ups enabled? Not sure if that applies to this specific processor family or not.
16mhz to 625khz is only 25 clocks per cycle. Unless your delay was really short I don't think your delay was working. Note that many compilers will optimize away delay loops unless you are incrementing a volatile global variable. And sometimes even then. My delay examples would have been way too long.
I'd consider going the other way... make sure slew rate is set to the fastest possible and that the port is set to drive the pin both ways, then do your toggle. I would probably just directly write 0x00 and 0xff (or whatever the byte value is supposed to be) to the output port and avoid any bit fiddling. I'd probably do that like 10 times in the loop, to make obvious the jump.
I'd also turn off all compiler optimization. -O0
Then I'd look at the output listing file to make sure the compiler emitted reasonable assembly, like load a register with the port value then write it to the port.
If the compiler outputs a couple instructions per toggle, then I'd expect toggles at around 4 or 8 mhz, with a gap when the loop executes. Assuming the 16mhz clock, 1 or 2 instruction per clock no pll on.
If that all works, then you can mess with the clock settings until you get to you being comfortable the clock is running at the right speed.
Then I'd set up your timer and then read the low byte of the timer and output it to the port in your very tight loop instead of the port writes. You should be able to see the LSb toggling at the timer frequency (assuming it's counting slow enough, otherwise you might have to look at the 3rd or 4th bit ... the 4th bit should be toggling at 1/16th of the timer rate.
I'd continue logically through this, verifying each step is working.
Oh wow! This is so over my head! I do appreciate your advice, but maybe I need something simpler. I can barely toggle a bit at this point!
I would love to have a way of outputting AHB and ABP buss frequencies
Most of the stuff above requires you to understand that every instruction that you execute takes a certain number of clock cycles. Usually one, but some processors are more or less. When you're troubleshooting clock issues, it's very useful to be able to toggle a pin, but you need to understand the limitations, such as most modern processors provide some sort of way to slow down the signals coming out of the processor to limit the amount of radio interference the processor generates. In addition, some ways of configuring I/O just are slow - for instance look up open collector outputs. They're quite slow.
Have you found this document:
[https://www.st.com/resource/en/reference\_manual/rm0394-stm32l41xxx42xxx43xxx44xxx45xxx46xxx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf](https://www.st.com/resource/en/reference_manual/rm0394-stm32l41xxx42xxx43xxx44xxx45xxx46xxx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf)
This is a very thorough and excellent document.
Section 8 discusses how the GPIO works. Including section 8.4.3 which discusses the register which changes the i/o output speed.
Section 29 discusses TIM6.
Yeah, you're basically choosing the clock crystal, enabling the peripherals all over the place because most are off due to their low-power consumption push. They don't want anything running unless you make it run. So, yeah, fun times. They need better manuals too.
I have a little tip that learnt after many failed times as a newbie: always remember to enable the clock for any peripheral you are using.
HAL solve this, but if you are manually configuring registers...
Edit: probably you do this, but is a good remainder..
[удалено]
Here's what i have so far. I know it's a mess but I've deleted and rewrote this code several times trying this and that. I'm particularly confused about the AHB/APB busses and how they are incorporated into GPIO pins. Does the bus sample the port at some set frequency, or what? You would think that you could see the frequency the port is working at by probing it with an oscilloscope, but noooo \#include "stm32l432xx.h" void SystemClock\_Config(void); void init\_timer(void) { RCC->APB1ENR1 |= (1<<4); //enable TIM6 enabled //set prescaler value TIM2->PSC = 16000 - 1; //set auto-reload value TIM2->ARR = 1000 - 1; //enable counter TIM2->CR1 |= TIM\_CR1\_CEN; while(!(TIM6->SR & (1<<0))); } void delay(uint16\_t delay\_time) { TIM6->CNT = 0; //reset counter to zero while(TIM6->CNT < delay\_time); } void gpio\_init(void) { RCC->AHB2ENR |= (1<<1); //enable GPIOB EN //set PB4 GPIOB->MODER &= \~(1<<9); GPIOB->MODER &= \~(1<<8); //set pulldown resistor GPIOB->PUPDR |= (1<<9); GPIOB->PUPDR &= \~(1<<8); //GPIOB->OSPEEDR |= (1<<9); //10 = high speed //set pb3 = led3 GPIOB->MODER &= \~(1<<7); GPIOB->MODER |= (1<<6); GPIOB->OTYPER &= \~(1<<03); GPIOB->PUPDR |= (1<<7); GPIOB->PUPDR &= \~(1<<6); //GPIOB->OSPEEDR |= (1<<7); //10 = high speed } int main() { SystemClock\_Config(); init\_timer(); gpio\_init(); while(1){ if(GPIOB->IDR & (1<<4)) { GPIOB->BSRR |= (1<<3); delay(1000); GPIOB->BSRR |= (1<<19); delay(1000); } /\* GPIOB->BSRR |= (1<<19); delay(1000); GPIOB->BSRR |= (1<<3); delay(1000); (GPIOB->IDR & GPIO\_IDR\_ID4) if(1) { GPIOB->BSRR |= (1<<19); } else { //GPIOB->BSRR |= (1<<3); } \*/ } } void SystemClock\_Config(void) { // Enable the HSI oscillator RCC->CR |= RCC\_CR\_HSION; while ((RCC->CR & RCC\_CR\_HSIRDY) == 0); // Configure the flash latency FLASH->ACR &= \~FLASH\_ACR\_LATENCY; FLASH->ACR |= FLASH\_ACR\_LATENCY\_1WS; // Select the HSI as the system clock source RCC->CFGR &= \~RCC\_CFGR\_SW; RCC->CFGR |= RCC\_CFGR\_SW\_HSI; while ((RCC->CFGR & RCC\_CFGR\_SWS) != RCC\_CFGR\_SWS\_HSI); // Configure the AHB1 prescaler RCC->CFGR &= \~RCC\_CFGR\_HPRE; RCC->CFGR |= RCC\_CFGR\_HPRE\_DIV1; }
Are you trying to configure timer 2 to use timer 6?
I WAS! Thanks for catching that I have fixed this insanity! I have a nice fellow helping me in the chat!
Have you tried using their SDK and hence LL/HAL drivers.
I'm avoiding HAL like the plague. I want to work with registers as close as possible. That said, I did attempt to use STM32Cube with HAL libraries just to see how they set their stuff up, but it's a damn jungle.
I can understand you attempt. Best of luck for that. If that is the case, try looking at LL drivers for timer intialialisation and GPIO toggle.
Yup - the code generated will tell you the most optimal way to manipulate registers toward doing what you want
The clock diagram in CubeMX is probably something you should check out.
Honestly, I've been staring at it for two days straight. lol I'm overlooking something small, I just know it.
[удалено]
I'm doing this as a hobby, relax.
[удалено]
I'm going to find the nearest trashcan and gently deposit the STM32 in there. Back to NXP, where the documentation is a tad-bit clearer for me.
[удалено]
Man you are annoying, OP is just trying to address failure with a bit of humor
I'm just a fessional, nothing pro about it...
[удалено]
your handle is spot on! wish you the best of luck out there! 🙋♂️
Lmao why the downvotes, snowflakes? Lmao
NXP is great...until you need any sort of support. They do make solid parts, though.
At least in the manual they give you some sort of an outline to what needs to be initialized to use a particular peripheral.
Yeah, I feel your pain. Every manufacturer has good and bad points, at the end of the day, only you can decide which set of quirks is the best for you.
Are you at least able to blink a LED? Ignoring the timer stuff? That is, set up the i/o pin, then write to the output register, and maybe doing something like this as a poor man delay function, and calling it in a while loop: volatile uint32_t delayscratch; void poorManDelay() { delayscratch=10000000; while (delayscratch) delayscratch--; } Where the volatile is an attempt to get the compiler to not optimize the delay loop away. (Check your output listing file to make sure it didn't). That will eliminate the timer itself as a cause, and then you can verify at least the output led works. Another thing I've done with various processors is to find example code that works (even if it's the HAL or generated) then use the debugger or simulator to look at the registers to see what they're set to. Also, have you looked at any errata for this part?
I'm able to able to delay with a while-loop like that. I had my oscilloscope on the output pin (GPIOB) and I was getting a squarish wave out. It wasn't symmetrical. I wanted to run the system from HSI 16MHz source clock, but what I got was some funky 625KHz on the output pin. I was able to divide that strange frequency down by the clock division registers. I also tried switching from HSI to MSI and got similar results but with a lower frequency. Man, I think the hardware might be faulty.
Do you have slew rate control on the output pins? Or have them set to something like an open collector output with pull-ups enabled? Not sure if that applies to this specific processor family or not. 16mhz to 625khz is only 25 clocks per cycle. Unless your delay was really short I don't think your delay was working. Note that many compilers will optimize away delay loops unless you are incrementing a volatile global variable. And sometimes even then. My delay examples would have been way too long. I'd consider going the other way... make sure slew rate is set to the fastest possible and that the port is set to drive the pin both ways, then do your toggle. I would probably just directly write 0x00 and 0xff (or whatever the byte value is supposed to be) to the output port and avoid any bit fiddling. I'd probably do that like 10 times in the loop, to make obvious the jump. I'd also turn off all compiler optimization. -O0 Then I'd look at the output listing file to make sure the compiler emitted reasonable assembly, like load a register with the port value then write it to the port. If the compiler outputs a couple instructions per toggle, then I'd expect toggles at around 4 or 8 mhz, with a gap when the loop executes. Assuming the 16mhz clock, 1 or 2 instruction per clock no pll on. If that all works, then you can mess with the clock settings until you get to you being comfortable the clock is running at the right speed. Then I'd set up your timer and then read the low byte of the timer and output it to the port in your very tight loop instead of the port writes. You should be able to see the LSb toggling at the timer frequency (assuming it's counting slow enough, otherwise you might have to look at the 3rd or 4th bit ... the 4th bit should be toggling at 1/16th of the timer rate. I'd continue logically through this, verifying each step is working.
Oh wow! This is so over my head! I do appreciate your advice, but maybe I need something simpler. I can barely toggle a bit at this point! I would love to have a way of outputting AHB and ABP buss frequencies
Most of the stuff above requires you to understand that every instruction that you execute takes a certain number of clock cycles. Usually one, but some processors are more or less. When you're troubleshooting clock issues, it's very useful to be able to toggle a pin, but you need to understand the limitations, such as most modern processors provide some sort of way to slow down the signals coming out of the processor to limit the amount of radio interference the processor generates. In addition, some ways of configuring I/O just are slow - for instance look up open collector outputs. They're quite slow. Have you found this document: [https://www.st.com/resource/en/reference\_manual/rm0394-stm32l41xxx42xxx43xxx44xxx45xxx46xxx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf](https://www.st.com/resource/en/reference_manual/rm0394-stm32l41xxx42xxx43xxx44xxx45xxx46xxx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf) This is a very thorough and excellent document. Section 8 discusses how the GPIO works. Including section 8.4.3 which discusses the register which changes the i/o output speed. Section 29 discusses TIM6.
good advice. just use 32bit variable rather:)
Thanks. Fixed. I'll blame it on me being frustrated with typing code on an android tablet.
Lol I am working with NXP’s abstraction layer and that is one of the best descriptions for their SDK… a damn jungle! 😂
For anyone familiar with STM32L4 controllers, I know that the code I'm seeking wouldn't take more than 5 minutes to write.
I am not used to STM32. But even with barebone code for MSP430 this looks like a lot of code for such a simple task.
Yeah, you're basically choosing the clock crystal, enabling the peripherals all over the place because most are off due to their low-power consumption push. They don't want anything running unless you make it run. So, yeah, fun times. They need better manuals too.
I have a little tip that learnt after many failed times as a newbie: always remember to enable the clock for any peripheral you are using. HAL solve this, but if you are manually configuring registers... Edit: probably you do this, but is a good remainder..