I have the following code for ATMega128:
Some libraries and functions are not used as I haven't completed the code completely because I am stuck at this problem for days now.
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/delay.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define F_CPU 8000000UL
#define BAUDRATE 9600
#define UBRR_VALUE ((F_CPU)/(16UL*BAUDRATE))-1 //For UBRR registers
#define MASTER_WATCHDOG_MENU "\rEnter MS WD Choice (& period):\rA-30ms\rB-250ms\rC-500ms\rYour input:\0"
#define SLAVE_WATCHDOG_MENU "\rEnter SLV WD Choice (& period):\rA-0.5s\rB-1.0s\rC-2.0s\rYour input:\0"
#define USER_MENU "\rEnter choice (and period): 1-Mem Dump 2-Last Entry 3-Restart\rYour input:\0"
void ConfigureXMEMMode(void){
MCUCR |= (1 << SRE);
XMCRA = 0;
XMCRB = (1 << XMM2) | (0 << XMM1) | (1 << XMM0);
}
void ConfigureUSARTInterfaces(void){
UBRR0H = (unsigned char)(UBRR_VALUE >> 8);
UBRR0L = (unsigned char)(UBRR_VALUE);
UBRR1H = (unsigned char)(UBRR_VALUE >> 8);
UBRR1L = (unsigned char)(UBRR_VALUE);
UCSR0B = (1<<RXEN0) | (1<<RXCIE0) | (1<<TXEN0) | (1<<TXCIE0);
UCSR1B = (1<<RXEN1) | (1<<RXCIE1) | (1<<TXEN1) | (1<<TXCIE1);
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
UCSR1C = (1 << UCSZ01) | (1 << UCSZ00);
}
void USART0_TransmitByte(unsigned char byteToTransmit){
while(!(UCSR0A & (1<<UDRE0)));
UDR0 = byteToTransmit;
}
void USART0_TransmitString(unsigned char *stringToTransmit){
unsigned char i = 0;
for(i = 0; stringToTransmit[i] != '\0'; i++){
USART0_TransmitByte(stringToTransmit[i]);
}
}
void USART1_TransmitByte(unsigned char byteToTransmit){
while(!(UCSR1A & (1<<UDRE1)));
UDR1 = byteToTransmit;
}
void USART1_TransmitString(unsigned char *stringToTransmit){
unsigned char i = 0;
for(i = 0; stringToTransmit[i] != '\0'; i++){
USART1_TransmitByte(stringToTransmit[i]);
}
}
unsigned char USART0_ReceiveByte(void){
while(!(UCSR0A & (1<<RXC0)));
return UDR0;
}
unsigned char USART1_ReceiveByte(void){
while(!(UCSR1A & (1<<RXC1)));
return UDR1;
}
void ConfigureWatchdogTimer(void){
while(EECR & (1 << EEWE));
EEARH = 0x00;
EEARL = 0x00;
EECR = 1 << EERE;
if(EEDR == 0xFF){
EEARL = 0x01;
if(EEDR == 0xFF){
EECR = 0 << EERE;
ConfigureMasterWD();
}
}
while(EECR & (1 << EEWE));
EEARH = 0x00;
EEARL = 0x02;
EECR = 1 << EERE;
if(EEDR == 0xFF){
EEARL = 0x03;
if (EEDR == 0xFF){
EECR = 0 << EERE;
ConfigureSlaveWD();
}
}
}
void ConfigureMasterWD(){
USART0_TransmitString(MASTER_WATCHDOG_MENU);
unsigned char userInput = USART0_ReceiveByte();
switch(userInput){
case 'A': case 'a':
WDTCR = (1 << WDE) | (0 << WDP2) | (0 << WDP1) | (1 << WDP0); //30ms
break;
case 'B': case 'b':
WDTCR = (1 << WDE) | (1 << WDP2) | (0 << WDP1) | (0 << WDP0); //250ms
break;
case 'C': case 'c':
WDTCR = (1 << WDE) | (1 << WDP2) | (0 << WDP1) | (1 << WDP0); //500ms
break;
}
USART0_TransmitString("\rDone!\r");
}
void ConfigureSlaveWD(){
USART0_TransmitString(SLAVE_WATCHDOG_MENU);
unsigned char userInput = USART0_ReceiveByte();
switch(userInput){
case 'A': case 'a':
WDTCR = (1 << WDE) | (1 << WDP2) | (0 << WDP1) | (1 << WDP0); //500ms
break;
case 'B': case 'b':
WDTCR = (1 << WDE) | (1 << WDP2) | (1 << WDP1) | (0 << WDP0); //1.0s
break;
case 'C': case 'c':
WDTCR = (1 << WDE) | (1 << WDP2) | (1 << WDP1) | (1 << WDP0); //2.0s
break;
}
USART0_TransmitString("\rDone!\r");
}
void Sleep(){
sei();
set_sleep_mode(SLEEP_MODE_IDLE);
sleep_enable();
sleep_cpu();
}
void WakeUp(){
sleep_disable();
cli();
}
int main(void){
ConfigureXMEMMode();
ConfigureUSARTInterfaces();
ConfigureWatchdogTimer();
USART0_TransmitString("ATMEGA128 TO USART0");
USART1_TransmitString("ATMEGA128 TO USART1");
Sleep();
while(1);
}
ISR(USART0_RX_vect){
WakeUp();
new_user_read_char = UDR0;
USART1_TransmitByte(UDR0);
Sleep();
}
When simulate this code on Proteus, I see that the whole main function is in an infinite loop as the virtual terminal continuously repeats the ConfigureWatchdogTimer() function. However, the behavior that I expect is, configuration functions only run once, the CPU goes to sleep mode and only wakes up when an interrupt happens, which for this code is receiving a byte on usart0. What am I missing here or what is it that I am not understanding? The interrupt that I wrote somewhat works as if I constantly spam a character, that character does show up in the other terminal every once in a while.
Behavior that I get on Proteus when I run this code on ATMega128
Occasional code restart is a usual sign of some missed interrupt handler.
For example, you have receive (RXCIEn) and transmission (TXCIEn) interrupts enabled for both USARTs in ConfigureUSARTInterfaces
:
UCSR0B = (1<<RXEN0) | (1<<RXCIE0) | (1<<TXEN0) | (1<<TXCIE0);
UCSR1B = (1<<RXEN1) | (1<<RXCIE1) | (1<<TXEN1) | (1<<TXCIE1);
but have only handler for USART0_RX_vect
.
Either define ISRs for other USARTs interrupts, or disable (do not set) corresponding TXCIE
/RXCIE
-bits in USART configurations