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.
Related
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.
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.
For an exhibition with some interactive installations, I have to create a system that reads data from three ultrasonic PING sensors and has a DMX dimmer connected at one output.
So I took my Arduino Mega board, built some hardware around it (signal inverter for DMX) and tested the DMX dimmer using the library DmXSimple. It works fine!
Next step: testing the PING sensors. I used the library NewPing, and connected the sensors. It works fine!
Now both together, in one program: Importing both libraries, using the same codes. It doesn't work!
Timer collision? Well...anyway - I have no idea on how to solve that. What should I do? If it's a timer issue (that is, both libraries call the same timer), I really don't know how to modify the libraries to get it working.
There are two timers on the Arduino, and you may be able to make both works aside. DmxSimple explicitly says it uses the timer #2, whereas it is not clear for NewPing. But the NewPing library can work without using a timer. You can make the DmxSimple work using its timer (which is mandatory for close-to-real-time interaction with its bus), whereas you can handle the sonar ping in the loop function:
void loop() {
int dst = sonar.ping_cm();
delay(50);
DmxSimple.write(1, dst);
}
There you shouldn't have timers conflicting.
Looking at the source code of NewPing, it uses Timer2 if you use the timer_us()/timer_ms() functions, but no timer otherwise. But if you run it on an Arduino Leonardo (or Arduino Micro or any other ATmega32U4 based microcontroller), it will use Timer4 which is not conflicting with DmxSimple.
If you want to patch the NewPing library to use Timer3, you may want to replace this in NewPing.cpp:
OCR2A = 249;
TIMSK2 |= (1 << OCIE2A);
with
OCR3A = 640;
TIMSK3 |= (1 << OCIE3A);
and in stop_timer:
TIMSK2 &= ~(1 << OCIE2A);
with
TIMSK3 &= ~(1 << OCIE3A);
I have a problem with set-up interruption flag in AVR AT90S2313. Normally interruption is setting-up through hardware counter. I want to setting this flag in programming way when I want (at the specific moment). I'm writing all code in C:
SEI(); //enable globall interupt
TIMSK | = (1<<TOIE1); //enable interrupt from timer 1
TIFR | = (1<<TOV1); //enable interruption (setting bit) - IT DOESN"T WORKS!
So, in the last line it should be programming interruption but nothing is happening and I don't know why. Any idea? Thanks in advance.
TIFR registers are special in that writing a 1 to a bit sets it to 0.
Edit in response to a comment:
You shouldn't be doing anything with the register as far as I can tell from what little information you have supplied. That is, don't try to use the interrupt mechanism to run the handler. At the point in your code where you want to trigger the interrupt, just call the handler yourself. You may also want to be adjusting the enable bits or clearing flags at the same time -- I don't know what you are trying to do.
If you want the handler to run as if it were acting in response to an interrupt, then you will want to disabled interrupts first. The usual way to do this is
void function_to_trigger_handler()
{
uint8_t sreg = SREG;
cli();
my_interrupt_handler();
SREG = sreg;
}