I'm facing a problem programming an ATmega32A-PU regarding the use of Interrupt INT0. Everytime it's triggered (by rising edge on PD2) , it causes the MCU to (seemingly) reset, meaning it starts int main(void) from the beginning.
It's not the first time, I'm working with Interrupts and I don't see why it should behave like it does.
Appart from that, I'm also making use of 'ISR(TIMER0_COMP_vect)', which work's just fine.
#define F_CPU 16000000 // 16 MHz clock speed
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
volatile unsigned int T2StopFlag = 0;
volatile unsigned int initialized = 0;
volatile unsigned long millis_value = 0;
#include "Includes\csrc\u8g2.h"
#include "display.h"
#include "utility.h"
// (utility.h includes:)
/* ----------------------------------------------------------------------- */
IRS(INT0_vect)
{
PORTA &= ~(1<<6); // MotorOFF();
PORTA &= ~(1<<4); // RV1OFF();
PORTA &= ~(1<<5); // RV2OFF();
T2StopFlag = 1; // T2StopFlag setzen
}
ISR(TIMER0_COMP_vect) // ISR for millis();
{
millis_value++; // Increment millisecond every 1ms
}
unsigned long millis()
{
unsigned long m;
cli();
m = millis_value;
sei();
return m;
}
/* ----------------------------------------------------------------------- */
#include "systemcheck.h"
#include "executions.h"
#include "states.h"
#include "modusoperandi.h"
/* ----------------------------------------------------------------------- */
int main(void)
{
// --- ISR for T2 (INT0) --- // <- Causes program to restart.
MCUCR = 0x03; // 0b 0000 0011 -> INT0 rising edge, INT1 not
GICR = 0x40; // 0b 0100 0000 -> INT0 set, INT1 set INT2 not
// --- ISR for millis(); --- // <- Works just fine.
TCCR0 = 0x0B; // Clock source: System Clock // Mode: CTC top=OCR0
TCNT0 = 0x00; // Timer/Counter 0 initialization
OCR0 = 0xF9; // Clock value: 250.000 kHz (16MHz/64)
TIMSK = 0x02; // Enable compare match interrupt for timer 0
// --- Enable global interrupt --- //
sei();
// ---- StartUp Sequence ---- //
StartUpSeqDemo(); // Run Start Up Sequence once
ServiceModeReq(); // Request Command to enter Service Mode
// ---- Loop ---- //
while(1)
{
/* ... */
} // while(1); end
} // int main(void); end
What I tried:
Implementing INT0 as a ISR at rising edge on PD2.
suspected cli(); and sei(); in millis() {...} to cause the problem but I'm not getting a different result when commenting them out.
DMFR
What I ecpected to happen:
Program does it's thing, IRS triggers on rising egde, program continues what it was doing.
What actually resulted:
Program restarts, code before while(1) {} is being executed.
What I also noticed
I'm getting the following warnings on IRS(INT0_vect) {...}, but not on ISR(TIMER0_COMP_vect):
Warning type of '__vector_1' defaults to 'int' [-Wimplicit-int]
Warning return type defaults to 'int' [-Wimplicit-int]
Warning control reaches end of non-void function [-Wreturn-type]
So I tried:
int IRS(INT0_vect)
{
PORTA &= ~(1<<6); // MotorOFF();
PORTA &= ~(1<<4); // RV1OFF();
PORTA &= ~(1<<5); // RV2OFF();
T2StopFlag = 1; // T2StopFlag setzen
return 0;
}
which reduces the warnings to:
Warning type of '__vector_1' defaults to 'int' [-Wimplicit-int]
Not quite sure I that's a related problem and wether thats a related problem.
Any thoughts are welcome.
Btw, please bear with me if I'm missing out on some information or something, I'll happily provide you with everything that helps.
Thanks for your time and effort!
Related
my microcontroller is attiny85.Actually I have a few questions.
I simply turn on the LED 8 seconds later with the code below.
1)Should I turn the interrupts off and on while reading the counter value? I've seen something like this in the wiring.c file, the millis function.
2)How can I safely set the counter variable to 0 whenever I want? Do I have to turn the interrupts off and on here? Should I set the variables TCCR0A, TCCR0A, TCNT0 to zero?How should a safe reset function be?
Actually, all my purpose is to make a safe counter in the main function that can count 8 seconds whenever I want and start from zero whenever I want.
My basic code in below :
#define F_CPU 1000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include <stdio.h>
volatile unsigned int counter = 0;
ISR(TIM0_COMPA_vect){
//interrupt commands for TIMER 0 here
counter++;
}
void timerprogram_init()
{
// TIMER 0 for interrupt frequency 1000 Hz:
cli(); // stop interrupts
TCCR0A = 0; // set entire TCCR0A register to 0
TCCR0B = 0; // same for TCCR0B
TCNT0 = 0; // initialize counter value to 0
// set compare match register for 1000 Hz increments
OCR0A = 124; // = 1000000 / (8 * 1000) - 1 (must be <256)
// turn on CTC mode
TCCR0A |= (1 << WGM01);
// Set CS02, CS01 and CS00 bits for 8 prescaler
TCCR0B |= (0 << CS02) | (1 << CS01) | (0 << CS00);
// enable timer compare interrupt
TIMSK0 |= (1 << OCIE0A);
sei(); // allow interrupts
}
int main(void)
{
/* Replace with your application code */
timerprogram_init();
DDRA|=(1<<7);
PORTA &=~ (1<<7);
while (1)
{
if(counter>8000)
PORTA |= (1<<7);
}
}
First, there is no need to check the "counter" value in the super loop; In fact, this variable changes when an interrupt is created, so checking the variable should be done in the interrupt itself and if necessary, take only one flag from it.
Secondly, a safe way to reset the counter is to first deactivate the frequency divider(TCCR0B) of the timer section (the counter timer is practically turned off) and then set the TCNT0 value to zero to reset the timer; And if necessary, you can safely force the counter timer to count by returning the divider value.
Good luck.
The below is a code to enable interrupt INT0_vect when PD2 is pressed. The code doesn't ever execute the ISR, but always executes the counter loop from 0 to 9 on the 7 segment in PORT C in the main Function. Also tried the sei(); instead of enabling the I-bit in the SREG. Any ideas?
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define ISR_INT0_PD2 INT0_vect
ISR( ISR_INT0_PD2 ){
PORTC = 0x00;
_delay_ms(100);
}
int main(void)
{
int i=0;
DDRC=0xff; //portc is o/p
PORTC=0x00; // all pins on portc is 0 volt
MCUCR |= (1<<1); // falling edge
GICR |=(1<<6); // enable INT0 set pin6
SREG |=(1<<7); // set GIE pin7
while(1)
{
for(i=0;i<10;i++)
{
PORTC=i;
_delay_ms(1000);
}
}
}
[Below is the screenshot from the simulator I've been using]
For the interrupt to execute you need to call sei() defined in <avr/interrupt.h>.
https://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html#gaad5ebd34cb344c26ac87594f79b06b73
EDIT: I was mistaken when I removed the line SREG |= (1 << 7) according to my link that is equivalent to sei(); After I wrote the below example I realized the registers are named differently on the ATMega32, so unfortunately the code below won't run.
Based on the data sheet for an ATMega32 your code should work, have you tried removing the for loop and driving PORTC to logic high (e.g. PORTC = 255)? I noticed when I was writing the code for the ATMega168 that the LED I was using was very dim with the code in your while loop. Also check that INT0 pin is connected via pull-up/pull-down resistor.
This is the code that works on my ATMega168, if I swap the register names to the ones used on the ATMega32 I end up with your code:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define ISR_INT0_PD2 INT0_vect
ISR( ISR_INT0_PD2 ){
// If there is a logic change on any pin hold the pins attached to PORTC low for 100ms.
PORTC = 0;
_delay_ms(100);
// Relase PORTC to logic high.
PORTC = 255;
}
int main(void)
{
DDRC = 255; // Set all pins on PORTC to be outputs.
PORTC= 255; // Set all pins on PORTC to be logic high.
EIMSK = 0b00000001; // Set external interupt request enable.
EICRA = 0b00000001; // Set the external interrupt control register A to so that
// any logical change on INT0 generates an interrupt request.
sei(); // Set global interupts enable.
while(1)
{
PORTC=255; // Blink the entire PORTC bank.
_delay_ms(20);
PORTC=0;
_delay_ms(20);
}
}
This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 4 years ago.
I'm not really that familiar with C so please bear with me...
I'm writing some simple code for a watchdog timer on an Atmel Tiny 85, developing in AtmelStudio. I want to access the clock() function of the time.h library:
#include <time.h>
.....
void main() {
clock_t start = clock();
....
}
Unfortunately the compiler complains that clock is an undefined reference. Every code example I have looked up on the web seems to be doing what I am doing. Is there some fundamental thing I am missing? Thanks!
Here is the full code:
#define F_CPU 1000000UL // 1 MHz
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <time.h>
#include <stdio.h>
#include <avr/wdt.h>
#include <stdint.h>
#include <util/atomic.h>
#define LED_PORT PB1
#define RST0_PORT PINB3
#define RST1_PORT PINB4
#define HEARTBEAT PINB0
volatile int HEARTBEAT_RECEIVED;
#define CLOCKS_PER_SECOND 1000000;
const int TIMEOUT_PERIOD = 120; //reset raspberry pi after this many seconds
void set_output();
void set_input();
void set_interrupts();
void run_timer(clock_t start);
void restart_raspberry_pi();
int main(void)
{
clock_t start;
HEARTBEAT_RECEIVED = false;
//Configure IO pins
set_output();
set_input();
PORTB &= ~(1 << RST0_PORT); // Set pin low (common ground pin for pi reset)
PORTB &= ~(1 << RST1_PORT); // Set pin low (initialize for no pi reset)
//Configure and enable interrupts
set_interrupts();
while (1) {
sei();
start = clock();
run_timer(start);
}
return (0);
}
void run_timer(clock_t start) {
double time_elapsed;
do {
_delay_ms(1000);
if (HEARTBEAT_RECEIVED) { //If heartbeat detected, reset timer.
HEARTBEAT_RECEIVED = false;
return;
}
time_elapsed = ( clock() - start ) / CLOCKS_PER_SECOND;
} while (time_elapsed < TIMEOUT_PERIOD);
restart_raspberry_pi(); //Timeout period has elapsed, reset the pi
}
ISR(PCINT0_vect) {
//Indicate that a heartbeat has been received
HEARTBEAT_RECEIVED = true;
}
void restart_raspberry_pi() {
cli();
PORTB |= (1 << RST1_PORT); // Set pin high (sets RUN high to reset)
_delay_ms(500);
PORTB &= ~(1 << RST1_PORT); // Set pin low (release reset control)
}
void set_output()
{
//The DDxn bit in the DDRx Register selects the direction of this pin.
//If DDxn is written logic one, Pxn is configured as an output pin.
//If DDxn is written logic zero, Pxn is configured as an input pin.
//PORTB = (0<<PB0) | (1<<PB3);
DDRB = (1<<DDB5) | (1<<DDB4) | (1<<DDB3) | (1<<DDB2) | (1<<DDB1); // Set pins as output.
}
void set_input()
{
DDRB |= (0<<DDB0); // set pin 0 as input. Added |=.
}
void set_interrupts()
{
GIMSK |= (1 << PCIE); // pin change interrupt enable
PCMSK |= (1 << PCINT0); // pin change interrupt enabled for PCINT0
}
#Shawn had it right....I dove into the time.h library code available to me and apparently:
Section 7.23.2.1 clock()
The type clock_t, the macro CLOCKS_PER_SEC, and the function clock() are not implemented. We
consider these items belong to operating system code, or to application code when no operating
system is present.
So I guess that's a lesson for me. Thanks for the help.
I've been trying to turn on the LEDs on my MSP430G2553 and it just doesn't work. I've tried the code examples from TI, the pre-generated code composer studio LED blinking project, and even previous code that worked on an MSP430 from the past. None of them seem to work. What could be the problem? Could it be faulty hardware? Here's my code:
#include <msp430.h>
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
P1DIR |= 0x01; // Set P1.0 to output direction
for (;;)
{
volatile unsigned int i;
volatile unsigned int j;
P1OUT ^= 0x01; // Toggle P1.0 using exclusive-OR
i = 25000; // Delay
while(i--) {
j = 2;
while(j--);
}
}
}
I encountered a problem with the MSP430FR5994 dev board where the LEDs wouldn't turn on for the blinky example but they would turn on for the "Out Of Box Experience" project. Comparing the code, I determined that the difference is this line from pmm.c:
//For FRAM devices, at start up, the GPO power-on default
//high-impedance mode needs to be disabled to activate previously
//configured port settings. This can be done by clearing the LOCKLPM5
//bit in PM5CTL0 register
PM5CTL0 &= ~LOCKLPM5;
Putting that at the top of main() seems to fix whatever the issue is and the LEDs behave as expected.
Can you try this version (still a polling loop, but let's keep it very basic)?
#include <msp430.h>
int main(void) {
volatile int i;
WDTCTL = WDTPW | WDTHOLD;
P1DIR |= 0x01;
P1OUT = 0x00;
for (;;) {
P1OUT ^= 0x01;
for (i = 0x6000; i > 0; i--) { };
}
return 0;
}
I took this from one of my old examples when I used the MSP430 in 2010...
Try replacing your while loop with __delay_cycles(1000000);.
Compilers can optimize-out empty loops even if the loop variable is marked as volatile.
#include <msp430.h>
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
P1DIR |= 0x01; // Set P1.0 to output direction
for (;;)
{
P1OUT ^= 0x01; // Toggle P1.0 using exclusive-OR
__delay_cycles(1000000);
}
}
After a reset, all port pins are high-impedance with Schmitt triggers and their module functions disabled to prevent any cross currents. Even if you have made all the necessary GPIO settings, you need to clear LOCKLPM5 bit in the PM5CTL register (described in the I/O Configuration After Reset chapter TI User Guide)
PM5CTL0 &= ~LOCKLPM5;
until then, the I/Os remain in their high-impedance state with Schmitt trigger inputs
disabled.
I'm trying to convert an old ASM programme to C.
I'm quite sure I extracted all the logic needed, but it simply doesn't work.
My goal is to use a timer compare match to toggle output pin, generating a buzz for speaker.
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdint.h>
// speaker pin
#define SPK _BV(PA0)
#define SYSPORT PORTA
#define SYSPIN PINA
#define SYSDDR DDRA
ISR(TIMER1_COMPA_vect)
{
SYSPIN |= SPK; // toggle speaker
}
void main()
{
cli(); // disable all interrupts
SYSDDR = 0b00000001; // SPK to output
SYSPORT = 0b00000001; // turn off SPK
TCCR0A = _BV(WGM01); // CTC mode
TCCR0B = _BV(CS01) | _BV(CS00); // Prescaler 64
OCR0A = 62; // compare match = 62 (output freq 1kHz)
TIMSK = _BV(OCIE0A); // enable timer interrupt
sei(); // enable all interrupts
while(1) {} // infinite loop.
}
This code does not make a single beep, not even clicking, nothing at all.
However, when I just use a loop and delay, it works beautifylly - proving the speaker is connected properly.
I cannot do this though, I have to do something else while it is making the sound.
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/delay.h>
#include <stdint.h>
// speaker pin
#define SPK _BV(PA0)
// PORTA
#define SYSPORT PORTA
#define SYSPIN PINA
#define SYSDDR DDRA
void main()
{
SYSDDR = 0b00000001; // SPK to output
SYSPORT = 0b00000001; // turn off SPK
while(1) {
_delay_us(100);
SYSPIN |= SPK;
}
}
Fuses are set to
LFUSE = 0xE2
HFUSE = 0xDF
Frequency 4MHz.
Oh lol, I'm so inattentive
This should have been
ISR(TIMER0_COMPA_vect)
instead of
ISR(TIMER1_COMPA_vect)
It was handling a different timer :D