MSP430 ACLK problems after reset - c

I have an MSP-EXP430G2ET launchboard which has msp430g2553 microcontroller. I bought it for my embedded systems course.
Lately we learned to use timers and the last lab work was using the watchdog timer in time interval mode. But while doing that I figured out my ACLK was not working properly. I check the datasheet and guide for the board and It has ACLK if I'm not mistaken. By the way when I touch the pins of the board LED blinks at different frequencies.
This is the code that I used for the watchdog timer to light a LED with a period.
#include <msp430.h>
int main(void)
{
WDTCTL = WDTPW | WDTCNTCL | WDTIS0 | WDTSSEL | WDTTMSEL;// config watchdog timer aclk 1ms
P1DIR |= BIT0 | BIT6; // P1.0 and P1.6 is configured as output
P1OUT = ~BIT0 | ~BIT6; // Led P1.0 and P1.6 are turned off
while (1){
if (IFG1&BIT0 != 0){
P1OUT ^= BIT0 | BIT6;
IFG1 &= ~WDTIFG;
}
}
}
This code does not work. LED does not light up.

From the code snippet nothing looks outrageously wrong so without a device at my disposal I will take 4 stabs in the dark.
Make sure the correct msp430 is chosen in your project. msp430.h can lead to any of the msp430 headers depending on a define, a wrong one can mess with your project.
I would advise using the WDT_ADLY_XXX defines to set WDT_CTL. They're more legible.
It is advised that you place the watchdog in hold (WDTPW|WDTHOLD) before changing it's settings. It may be freaking out and resetting your device while you attempt to set it up.
P1OUT = ~BIT0|~BIT6 has wrong operator prescience. Each NOT is done before the OR. This does not have the same effect as ~(BIT0|BIT6) which ORs them together and then NOTs.

Related

STM32 Bare Metal C - Can't get LED to work

So I'm currently following a course for the STM32 Microprocessor however, I seem to fail at even the most basic thing: turning a LED on. The complete code is at the bottom of this post.
Important:
The hardware is functioning properly.
I am using a STM32L432KC.
First of all, we have to figure out on what pin the built-in LED is. According to the manufacturers manual, the LED should be on pin D13 (PB3).
Okay so we're looking for PB3. According to the datasheet of the STM32L432KC, PB3 is on the B port and therefore connected to the high performance bus as suggested in the image below.
Cool. So our bus is AHB2 and we're working with GPIOB. Now we have to enable the clock on that bus using the RCC_AHB3ENR register. Now, this is the part where I'm probably going to make mistakes (as this post otherwise wouldn't exist), so please pay close attention. If I understand correctly, I want bit 1 to be set to 1 as this indicates that 'GPIOBEN' is set to 'IO port B clock enabled.'.
This leads me to believe that I should set the bus register as follows:
RCC->AHB2ENR |= 0x2;
Next up I have to set the mode of the GPIO pin to output. According to the course and my documentation, this is done using GPIOx_MODER.
This leads me to believe that I should set the GPIO mode as follows:
GPIOB->MODER |= 0x40;
And last but not least to turn the actual LED on we have to set the output data register which is GPIOx_ODR.
This leads me to believe that I should set the data as follows:
GPIOB->ODR = 0x8;
I'm not sure where I'm going wrong but this is the first time I'm working with registers on such a deep level. I must be overlooking something but I've tried multiple examples and had no success. All help is appreciated.
This is the complete code:
// PB3 - User LED
// RCC->AHB2ENR
// GPIOx_MODER
// GPIOx_ODR
#include "stm32l4xx.h"
int main(void)
{
RCC->AHB2ENR |= 0x2;
GPIOB->MODER |= 0x40;
while(1)
{
GPIOB->ODR = 0x8;
}
}
Your mode register is not configured correctly. Your line of code
GPIOB->MODER |= 0x40;
can only set bits, it cannot clear them. And you have too many bits set, as the reset value of each pair is 11 and the entire register is FFFF FFFF for ports C-E, FFFF FEBF for port B.
You should use
GPIOB->MODER = (GPIOB->MODER & 0xFFFFFF3F) | 0x00000040;
although because the reset state is guaranteed, this will also work:
GPIOB->MODER &= 0xFFFFFF7F; // equivalently, ~0x0080
The note in the documentation of 11 analog mode (reset state) is not accurate for all pins. Several are in 10 alternate function mode at reset, including PB3. So you need to both clear one bit and set one.

Why is the PLL not locking? Is my clock configuration correct?

I am using the stm32l412kb for UART communication. I am trying to configure the USART2 peripheral clock to a 72MHz frequency. The stm32, after reset, uses the MSI at 4MHz, which I then use the PLL to extend to 72MHz when reaching the peripheral.
The code holds at the first PLLRDY check, as the PLL I assume is not locking. Could this be due to a too high a frequency output? Have I configure everything correctly? How do I know that the PLL is then being used instead of the 4MHz MSI, or the 24MHz HSE?
'''
void configureClocks(){
/*Clock Configuration
* The MSI (at 4MHz) is used as system clock source after startup from Reset.
* */
/*Turning on the medium speed internal clock (making sure it's on)*/
RCC->CR |= RCC_CR_MSION;
RCC->CR |= RCC_CR_MSIPLLEN;
/*Waiting until clock is ready*/
while(!(RCC->CR & RCC_CR_MSIRDY));
/*Selecting the MSI (0010) as the MCU clock output*/
RCC->CFGR &= RCC_CFGR_MCOSEL_Msk;
RCC->CFGR |= (0b0010<<RCC_CFGR_MCOSEL_Pos);
/*Turn off PLL to allow to make changes*/
RCC->CR &= ~(RCC_CR_PLLON_Msk);
/*Make sure PLL is locked*/
while(!(RCC->CR & RCC_CR_PLLRDY));
/*At 4Mhz, (4*36/2 = 72Mhz)*/
RCC->PLLCFGR &= ~(RCC_PLLCFGR_PLLN_Msk | RCC_PLLCFGR_PLLM_Msk);
RCC->PLLCFGR |= (2 << RCC_PLLCFGR_PLLM_Pos) | (36 << RCC_PLLCFGR_PLLN_Pos);
/*Turning back on the PLL clock*/
RCC->CR |= RCC_CR_PLLON;
/*Waiting until clock is ready*/
while(!(RCC->CR & RCC_CR_PLLRDY));
/*Selecting the PLL (0101) as the microcontroller clock output*/
RCC->CFGR &= RCC_CFGR_MCOSEL_Msk;
RCC->CFGR |= (0b0101<<RCC_CFGR_MCOSEL_Pos);
/*Enabling the USART2 peripheral clock.*/
RCC->APB1ENR1 &= ~(RCC_APB1ENR1_USART2EN_Msk);
RCC->APB1ENR1 |= (0b1 << RCC_APB1ENR1_USART2EN_Pos);
/*Enabling the GPIOA port peripheral clock*/
RCC->AHB2ENR &= ~(RCC_AHB2ENR_GPIOAEN_Msk);
RCC->AHB2ENR |= (0b1 << RCC_AHB2ENR_GPIOAEN_Pos);
return;
}
'''
Your responses are always much appreciated,
Many thanks,
Harry
Update, thanks to comments:
The first PLL check has been changed from:
while(!(RCC->CR & RCC_CR_MSIRDY));
to:
while(RCC->CR & RCC_CR_MSIRDY);
However, the PLL check still gets stuck on the second one.
Please refer to the Reference Manual (pdf) section 6.2.3 "MSI clock", "Hardware auto calibration with LSE (PLL-mode)" and section 6.4.1 "Clock control register (RCC_CR)"
There is in your code:
RCC->CR |= RCC_CR_MSIPLLEN;
But before enabling PLL mode on the MSI clock you have two things to be done:
External low-frequency resonator or oscillator should be installed (e.g. 32768Hz clock quartz)
As said in the Bit 2 MSIPLLEN description: MSIPLLEN must be enabled after LSE is enabled (LSEON enabled) and ready (LSERDY set
by hardware).There is a hardware protection to avoid enabling MSIPLLEN if LSE is not
ready.
So, if you have LSE installed, first you have to turn it on, and wait until it ready:
RCC->BDCR |= (RCC_BDCR_LSEON);
/*Make sure LSE is ready*/
while(!(RCC->BDCR & RCC_BDCR_LSERDY));
But probably you don't have to use PLL function of the MSI, because USART much more tolerant to frequency deviations. Then MSI-PLL mode should be kept disabled.
STM32 MCUs have some protection mechanics to avoid wrongly switch the clock source. Some bits cannot be set until clock source is ready, or cannot be cleared if the clock source is in use. They are described in the reference manual in bit descriptions.
So, please, carefully compare all steps you're doing to the manual.
UPD
As pointed out in another answer
/*Turn off PLL to allow to make changes*/
RCC->CR &= ~(RCC_CR_PLLON_Msk);
/*Make sure PLL is locked*/
while(!(RCC->CR & RCC_CR_PLLRDY));
You cannot have PLL locked when it is disabled. So, the while-loop will run forever.
UPD2
Before enabling the PLL you forget to set up it's source (bits PLLSRC in PLLCFGR). I.e.:
// set MSI as the source for PLL
RCC->PLLCFGR = (RCC->PLLCFGR & ~RCC_PLLCFGR_PLLSRC_Msk) | RCC_PLLCFGR_PLLSRC_MSI;
After disabling the PLL with RCC->CR &= ~(RCC_CR_PLLON_Msk); wait until PLLRDY is cleared.
Your code does the opposite, waits until PLLRDY is set, meaning it's locked. But you've just disabled it, so it's not going to lock.
After setting up PLLCFGR, turn it back on, and wait until PLLRDY is set. This part looks OK in the code.
When the PLL is running at the required speed, you should set the System clock switch (RCC_CFGR_SW) to PLL instead of the Microcontroller clock output to have your system run on the PLL clock.
Microcontroller clock output does something else. It can be connected to an external pin, to output the clock signal for using it outside the MCU, e.g. to synchronise several MCUs.
I always use Cube to see the clock tree. I also use registers - but that tool is very convenient and it prevents many stupid errors as it will let you know if the values are outside the recommended ones.
PS it should be a comment but I wanted to put the picture. So please do not UV or accept

Interrupt occurs from change that occurred before interrupt is enabled

I'm using an Arduino Uno with the Atmega328p microcontroller. I'm trying to use INT1 as a software interrupt. I manually set INT1's associated PORTD3 high or low depending on external info. What I want is to set the pin high or low at the startup of the device and then enable the interrupt on the pin without causing an interrupt if i set the pin high before enabling the interrupt.
It doesnt seem to matter where I enabled the interrupt--if i changed the state of the pin at some point the interrupt will occur once its enabled. Here is a snippet of the code:
int main(void)
{
DDRD |= (1<<DDD7)|(1<<DDD3);//7 for siren 3 for software int1
USART_Init(MYUBRR);//Initialize USART
while(door!='C' && door!='O'){//get door state on startup
door = getDoorState();
}
if(door=='O')
PORTD |= 1<<PORTD3;
else
PORTD &= ~(1<<PORTD3);
EIFR &= ~(1<<INTF1);//clear flag bit before enable, I'd heard this may help????
EIMSK |= (1<<INT1);//enable door switch interrupt
EICRA |= (1<<ISC00)|(1<<ISC10);//int1 and int0 set for any logical change
sei();//global interrupt enable
while (1)
{}
}
As soon as the global interrupt is enabled by a call to sei() the interrupt will occur if PORTD3 is high, regardless of where PORTD3 was set high or where sei() is. Calling sei() should never cause an interrupt in this code, ideally.
4386427 is correct. The bit is cleared by setting it to a one, not zero. Seems counter-intuitive to me so it threw me off but it works now.
EIFR |= (1<<INTF1);
EIFR &= ~(1<<INTF1) is incorrect.
The correct way of doing this is EIFR = 1<<INTF1.
Datasheet says: the flag is cleared by writing a '1' to it.

STM32L1x Stop mode + RTC too much current

I am able to put my stm32L1xDiscovery board in STOP mode with RTC running.
according to the datasheet this should draw about 1.3 µA. But my application draws 3.3 µA.
I noticed I did not put the FLASH in a low power mode during sleep. But when I did this, nothing changed.
This is what I use to go into STOP mode:
SCB->SCR |= ((uint32_t)SCB_SCR_SLEEPDEEP);
RCC->APB1ENR |= RCC_APB1Periph_PWR;
PWR->CR |= ((uint32_t)(PWR_CR_LPSDSR|PWR_CR_ULP)); // ULP seems to have no effect on power consumption
RCC->APB1ENR &= ~RCC_APB1Periph_PWR;
FLASH->ACR |= SLEEP_PD; // seems to have no effect at all on power consumption
__WFI();
Any idea what I am missing here?
If you use discovery board your measurement may be not clear because a lot of other components consumpt some energy. It's may be protection diode, driver of 3.3V line or second MCU with ST-LINK/V2 embedded debug tool.
Where did you measure the power consumption? You should do it betwen JP1 pins 1 & 2 (Pin 2 is connected directly to Vdd). That should show the power drawn by the MCU, and of course anything that is powered by the output pins.
The trick is to properly disconnect and shut down all pins (except the wakeup source) as well as all clocks that are not needed.
Set FLASH->ACR |= SLEEP_PD
Enable all GPIO clocks
Put all unneded pins to analog mode
Disable ALL clocks except RCC_APB1ENR_PWREN and wakeup GPIOs in RCC->xxxLPENR
Then start the thing without the debugger, ST-Link (CN3) jumpers removed.
... and there might be other issues. It's hard to get it right.

beginning with winAVR

I have 20 odd years in programming starting from pascal 7 to delphi. I want to start programming micro controllers using C and the tool most electronics kit recommend is winAVR with programmers notebook. I have installed the software and would like to start compiling code and I'm lost to say the least and can't find any simple documentation to get myself onto a track where I can start testing code. Can anyone offer some good starter material?
Whereas for PC's the usual first program is "Hello, World!", in the embedded world (one lacking displays, as least to start with, the equivalent is the blinky led: you attach a LED to some output pin of your processor (don't forget the current-limiting resistor!: you need a resistor in series with the LED), and you make the LED blink. You can find plenty of blinky LEDs for AVR, but we can write one right here:
// The next define tells delay.h what your CPU speed is, assuming 1Mhz
#define F_CPU 1000000UL
#include <util/delay.h>
main() {
while(1) { // loop forever
DDRB = 0xFF; // Set the direction of all pins
// on port B to OUTPUT (can change to some other port)
PORTb = 0xFF; // Set all pins on port B high (can change to some other port)
_delay_ms(1000); // Wait one second;
PORTb = 0x00; // Set all pins on port B low (can change to some other port)
_delay_ms(1000); // Wait one second;
}
}
It should compile on WinAVR, and load correctly. Change PORTB and DDRB to some other port of you'd like. Note that this program changes all the pins on that port: so if your port B has 8 pins, all of them will blink a led hooked up to them. Don't forget the current-limiting resistors, and that LEDs are directional: they only work when plugged in one way, and not the other.

Resources