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

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.

Related

STM32 Button Read

What is the difference between MODER's input mode and PUPDR. I saw some code parts for buttons. One code is like
GPIOB->MODER &= ~(3U << 2*4); // PB4
GPIOB->MODER |= (0U << 2*4);
and another code is,
GPIOB->MODER &= ~(3U << 2*8); //PB8
GPIOB->PUPDR |= (2U << 2*8);
should I make MODER register as an input like first one? But second one is just clearing MODER register and making PUPDR as Pull-up.
shouldn't I making MODER as input first?
The first code snippet, second line is doing nothing. Anything ORed with zero will keep its value.
In both snippets, the port is configured as an input by the first line. Pull-up/down is configured independently of the port mode, any port could be even configured as an output with pulls enabled (no idea why anyone would want it).
Internal pull is required if the circuit have no external one, to set the port level when button is not pressed.
The second snippet is setting pull-down for PB8, not pull-up. See snap from STM32F4 reference manual:
To read a button on STM32, you should adjust the MODER as input. Then, you can just check the IDR(Input Data Register).
For PUPDR, you need this register if you do not have any externally connected Pull-up or pull-down resistor.
The second code assigns the specific port as input with pull-down configuration, in your example. So it is your decision to make it either pull-down or pull-up.
The first code is doing the same thing twice on the both lines.

MSP430 ACLK problems after reset

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.

When on 4 bit data mode, is it possible to use the other 4 bits for other stuff?

So im writing a C program to interface an LCD on 4 bit data mode. However, I was wondering if I could use the other 4 bits to do something else like an external interrupt.
To be more specific, Im using PORTD for the data lines on the arduino however I also need pin PD2 to use the INT0 interrupt (pushbutton). In my program I noticed I kept setting the lower 4 bits to 0 when sending commands:
PORTD = cmd & 0xf0;
flashLCD();
PORTD = (cmd & 0x0f) << 4;
This works perfectly but it sets the other bits to 0. This is called on a timer which means Im sending commands repeatedly. Therefore, I tried saving the previous value of the register and append it with some bitwise operations:
uint8_t initial_state = PORTD;
PORTD = (cmd & 0xf0) | (initial_state & 0x0f);
flashLCD();
PORTD = ((cmd & 0x0f) << 4) | (initial_state & 0x0f)
It sends the cmd on the LCD, however it still wont respond to the interrupt. I wanted to know if theres something Im not taking into consideration or if my logic is incorrect. Thanks.
Edit: Nvm I figured it out. My LCD library resetted the port register to 0 always even when on 4 bit mode so the other unused ports were being reset as well. I just changed the library so that I can use the other ports when on 4 bit mode.
You correctly noted that other bits can be preserved by using the bitwise operations
PORTD = (PORTD & 0x0F) | (high_bits << 4);
But! this line is going to be compiled into several machine instructions:
load PORTD value into a register
perform bitwise AND on the register
load high_bits into another register
perform other calculations (left shift on the high bits etc.)
perform bitwise OR
store the result back into PORTD
Let's imagine, somewhere between 1 and 6 an interrupt fires, it stop the code execution, and it changes lower bits of PORTD. After the interrupt routine completes, the program continues to execute and it will rewrite all 8th bits of PORTD by what was stored in the registers before the interrupt, thus overwriting lower bits of PORTD, discarding all changes made in the interrupt routine.
So, there are two approaches to make write operation to PORTx atomic.
First: just disable interrupt for the time of PORTx register update:
uint8_t old_sreg = SREG; // save SREG register (including I flag)
cli(); // clear I flag, thus prohibiting interrupts
PORTD = (PORTD & 0x0F) | (high_bits << 4); // perform the operation
SREG = old_sreg; // restoring SREG and I flag, if it was set before
Second approach works only on new AVR cores (eg. ATmega328, 1284, 2560 etc), but will not work on older ones (ATmega8, 32 etc). Refer to the datasheet, I/O-Ports -> Ports as General Digital I/O -> Toggling the Pin section.
Writing ones into bits of PINx will invert corresponding bits of PORTx. Using it, it is possible to update only required bits of PORTx register, leaving other intact, thus removing need of locking out interrupts. It may be useful in time-critical environment, where interrupt should fire as quick as possible.
PIND = (PORTD ^ (high_bits << 4)) & 0xF0;
Of course it will work if it guaranteed the interrupt may change only other (in this example - lower) bits of the PORTD. If the interrupt can also write in the same bits, then this may cause unexpected results, so, be careful.
I do not know the controllers (ATmega/AVR or whatever) used on Arduino and you do not even specify, which one you use.
But usually, ports and port pins can be configured to have either input or output mode. Since you give out 4 bits over PORTD, I assume, the whole 8bit port (all port pins) are configured as output.
You should consider your manual, if certain pins of the whole port can be output pins while others can be input pins at the same time and how.
Be careful switching input/output of a whole port in between, it could have side effects, e.g. unwanted H-L / L-H transitions. I had this once with an 8255 output chip, causing resets of my graphic LCD, due to a connected reset line of the LCD.

How to use GPIO Port Control (GPIOPCTL) in ARM Cortex M4 TM4C123G microcontroller?

I am trying to interface an ultrasonic sensor with ARM Cortex M4 mcu. Since I am using and edge-triggered timer that calculates the time between the rising and falling edge of the echo of the sensor, What is the alternate function that I should be assigning to the echo input pin ?
I have found the following configuration on http://cortex-m.com/tm4c-lessons/:
void Timer0_init(void)
{
SYSCTL->RCGCTIMER |=(1U<<0);
SYSCTL->RCGCGPIO |=(1U<<1);
GPIOB->DIR &=~ECHO;
GPIOB->DEN |=ECHO;
GPIOB->AFSEL |=ECHO;
GPIOB->PCTL &=~0x0F000000;
GPIOB->PCTL |= 0x07000000;
TIMER0->CTL &=~1;
TIMER0->CFG =4;
TIMER0->TAMR = 0x17;
TIMER0->CTL |=0x0C;
TIMER0->CTL |=1;
}
I used the data sheet to understand every line but for the lines I don't understand :
GPIOB->PCTL &=~0x0F000000;
GPIOB->PCTL |= 0x07000000;
I guess the first line is just a reset , and the second line selects the peripheral function, but I can't undertstand or find what does setting the pin he used for input with 7 in the PCTL register ?
As described in the datasheet on page 688f the used bits 27:24 of this register are used to set the alternate function to be used on pin 6. According to GPIOB->PCTL the configured pin is PB6.
Now you can see on page 1351 Table 23-5 which alternate function is set. In this case it is T0CCP0 which is either a pwm, a capture or a compare funtcion based on the pin direction and peripheral configuration.
GPIOB->PCTL &=~0x0F000000; is used to reset the pin 6 function, without touching the other pins.
GPIOB->PCTL |= 0x07000000; sets the pin 6 function, without changing the others.

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.

Resources