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.
Related
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.
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.
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.
I am programming ATmega16 and I chose that controller in device manager(atmel studio 6.2) but the registers don't match with the registers in the datasheet for ATmega16. I am using ICE 3 and I tried with the simulator but it is the same result. Register UCSRC is different, from some other controller and can't write in it, even though I set MSB to one.
according to datasheet of ATMEGA16, it is not required to set MSB of UCSRC as its initial value is 1.
When you are working with UART you need to make sure that,
You are setting proper UBRRL and UBRRH, according to controller clock using formula as below:
FOSC/16/BAUD-1
Enable RXEN and TXEN from UCSRB
Set the proper bits in UCSRCaccording to your requirement of stop bit and parity bit
Please refer following image :
I am using an ATmega88PA to look for pin changes on 2 pins. I would like to use PCINT0 and PCINT2 although I have a lot of other pins open if I need to use a different pin. I have been messing around with things and was able to get PCINT0 to work properly, my problem came when I was trying to get PCINT2 to work.
If I define and set up PCINT2 the same way that I did to get PCINT0 to work nothing happens. I have tried this even in a new program just to see if something else was interfering in some way but that did not solve anything. I even got rid of PCINT0 all together to see if i could get PCINT2 to work on its own but I was still not able to.
Here is the code that I had for PCINT0
DDRC = 0x20; // PORTC,5 is now output
sbi(PORTC,5);
USART_Init(51);
lcd_init(LCD_DISP_ON);
lcd_clrscr();
PCICR |= (1 << PCIE0);
PCMSK0 |= (1 << PCINT0);
If I change everything to PCMSK2 and PCINT2 nothing happens when I trigger the pin. here is a link to the data sheet for the ATmega88PA Datasheet
I think this problem might be largely due to the slightly confusing names of the various register flags. If you stare at the datasheet long enough, you'll notice that PCIE2 and PCMSK2 do not control PCINT2. They actually control PCINT16 to PCINT23.
PCINT0-PCINT7 (which includes PCINT2, which you want) are controlled by PCIE0 in PCICR (which you already set) and PCMSK0 (not PCMSK2 which you mention in your last comment.)
So, to fix your problem, all you need to do is change your last line to:
PCMSK0 |=(1 << PCINT0) | (1 << PCINT2)
Disclaimer: I have not had a chance to test this on real hardware. Please double-check the datasheet.
Hope this helps.