4

I am using an ATmega32 to interrupt every 32ms to do some arbitrary stuff, which isn't really important for now.
I'm using the timer overflow of timer0 to interrupt, which works predictably and perfectly.

My problem is I have a global variable:

volatile int isSampling;

That isn't being written to in the interrupt vector. I read that the integer needed to be volatile to remove the possibility of compiler optimizations, but I declared it as volatile and its still not working.

#include <AVR/IO.h>
#include <util/delay.h> 
#include <avr/interrupt.h>

char studentID[12]            = {'S',1,2,3,4,5,6,7,'A','B','C','D'};

char buffer[72]; //Max bitlength = 6. * studentID length
char repcount[72];
int pointer;

volatile int isSampling;

void setup(void);
void startup(void);
void loadValue(unsigned char loadedValue);
void processValue(unsigned char processedValue, short bitLength);
void sendDot(void);
void sendDash(void);



int main(){

    setup();
    while(1)
    {

        if (isSampling == 1){
            startup();
            int i;
            for (i = 0; i < 12; i++){
                loadValue(studentID[i]);
                //Flash lights after letter sent.
                _delay_ms(500);
                PORTB = 0xF0;
                _delay_ms(500);
            }
        }
    }   
}

void setup(void){
    DDRB = 0xFF;
    sei();  
    TCCR0 = TCCR0 | 0x05;                   
    TIMSK|=(1<<TOIE0);  
    TCNT0 = 0;
    pointer = 0; 
    isSampling = 1;
}

ISR(TIMER0_OVF_vect)
{   
    //Every 32ms this interrupt vector is called.
    isSampling = 0;
}

void startup(void){
    //Play LED startup pattern
    int i;
    for (i = 0; i < 4; i++){
        PORTB = 0b11110011; //Bit 5 is constantly sampled. 4 is output
        _delay_ms(250);
        PORTB = PORTB & 0x00;
        _delay_ms(250);
    }
    _delay_ms(500);
    _delay_ms(500);
}

void loadValue(unsigned char loadedValue){
    switch (loadedValue){
        case   1: processValue(0b01111000, 5);
        case   2: processValue(0b00111000, 5);
        case   3: processValue(0b00011000, 5);
        case   4: processValue(0b00001000, 5);
        case   5: processValue(0b00000000, 5);
        case   6: processValue(0b10000000, 5);
        case   7: processValue(0b11000000, 5);
        case   8: processValue(0b11100000, 5);
        case   9: processValue(0b11110000, 5);
        case   0: processValue(0b11111000, 5);
        case 'A': processValue(0b01000000, 2);
        case 'B': processValue(0b10000000, 4);
        case 'C': processValue(0b10100000, 4);
        case 'D': processValue(0b10000000, 3);
        case 'E': processValue(0b00000000, 1);
        case 'F': processValue(0b00100000, 4);
        case 'G': processValue(0b11000000, 3);
        case 'H': processValue(0b00000000, 4);
        case 'I': processValue(0b00000000, 2);
        case 'J': processValue(0b01110000, 4);
        case 'K': processValue(0b10100000, 3);
        case 'L': processValue(0b01000000, 4);
        case 'M': processValue(0b11000000, 2);
        case 'N': processValue(0b10000000, 2);
        case 'O': processValue(0b11100000, 3);
        case 'P': processValue(0b01100000, 4);
        case 'Q': processValue(0b11010000, 4);
        case 'R': processValue(0b01000000, 3);
        case 'S': processValue(0b00000000, 3);
        case 'T': processValue(0b10000000, 1);
        case 'U': processValue(0b00100000, 3);
        case 'V': processValue(0b00010000, 4);
        case 'W': processValue(0b01100000, 3);
        case 'X': processValue(0b10010000, 4);
        case 'Y': processValue(0b10110000, 4);
        case 'Z': processValue(0b11000000, 4);
        case '.': processValue(0b01010100, 6);
        case ',': processValue(0b11001100, 6);
        case '?': processValue(0b00110000, 6);
        case '!': processValue(0b00110000, 5);
        case ':': processValue(0b11100000, 6);
        case '=': processValue(0b10001000, 5);
    }
}

void processValue(unsigned char processedValue, short bitLength){
    unsigned char result;
    int i;
    //Enter Loop at the length of bits in numerical morse code
    for (i = 0; i < bitLength; i++){
        result = processedValue & 0x80;
        processedValue = processedValue << 1;
        if (result) sendDash();
        if (!result) sendDot();
        _delay_ms(1000);
    }
}

void sendDot(void){
    //Send Dot
    PORTB = 0x05;
    _delay_ms(250);
    PORTB = 0x00;
}

void sendDash(void){
    //Send Dash
    PORTB = 0x06;
    _delay_ms(750);
    PORTB = 0x00;
}

Okay I have found the offending code that is causing the problem, but I am unsure why its causing it. When I remove loadValue(studentID[i]) from the main while loop, the code works as predicted. But when I put it back, it breaks again.

WedaPashi
  • 3,561
  • 26
  • 42
Ospho
  • 2,756
  • 5
  • 26
  • 39
  • Btw. I assume your using C code. C++ doesn't support default-int. – 0xbadf00d May 31 '11 at 13:24
  • 1
    For this extremely short program, I really suggest you read the generated assembly code. – unwind May 31 '11 at 13:32
  • You said "overflow of timer0 to interrupt, which works predictably and perfectly". Did you really verify that? If not, I suggest to insert some code in the ISR that toggles an output line and watch it with a scope. – Curd May 31 '11 at 13:39
  • I think the problem is, that the write access to "isSampling" isn't broadcastet to the main loop or it's never written to. – 0xbadf00d May 31 '11 at 13:41
  • Okay, i've added in the code as requested. I found the offending code, it seems to be the loadValue(studentID[i]) method thats causing it. I have no idea why though... – Ospho May 31 '11 at 13:51
  • And yes, I can verify that the interrupts are working, 100% – Ospho May 31 '11 at 13:52
  • 1
    @Oliver: I would hazard a guess that the `_delay_ms` function is messing with the interrupt mask somehow. Try simplifying the code down to a much simpler application, and see if you still get the issue. – Oliver Charlesworth May 31 '11 at 14:20
  • Add a default: arm to your switch statement. – John R. Strohm May 31 '11 at 14:23
  • 1
    @Oli Charlesworth. It seems your right, when I comment out all the _delay_ms functions the code works as predicted, its only once i put them in they mess with the global variable. I'm unsure, but perhaps maybe its due to the atomic nature of isSampling? Please answer the question so i can accept. Thanks. – Ospho Jun 01 '11 at 00:33
  • @Oliver: I don't understand how `_delay_ms` could be affecting the global variable; at most, I could imagine it clearing the interrupt mask so that your ISR is disabled some of the time. – Oliver Charlesworth Jun 01 '11 at 07:04

3 Answers3

2

The _delay_ms(500) lines are causing the problem as stated by Oli Charlesworth. The _delay_ms() function can cause unpredictable behavior if set to high (above 250ms).

Ospho
  • 2,756
  • 5
  • 26
  • 39
  • Why do you think there is unpredictable behavior? [Source:](http://www.nongnu.org/avr-libc/user-manual/group__util__delay.html) "The maximal possible delay is 262.14 ms / F_CPU in MHz. When the user request delay which exceed the maximum possible one, _delay_ms() provides a decreased resolution functionality. In this mode _delay_ms() will work with a resolution of 1/10 ms, providing delays up to 6.5535 seconds (independent from CPU frequency). The user will not be informed about decreased resolution." – Rev May 26 '16 at 06:05
1

Not sure if it explains the problem, but are you intentionally not having a break after each switch case value?

Nick Gorham
  • 1,118
  • 8
  • 9
  • It is a bug, that's for sure. Every time he tries to send the morse code of a letter, he ends up sending all letters after that letter as well. – vhallac Jun 20 '11 at 16:15
-2

the problem occurred on the definition of char array

char studentID[12]            = {'S',1,2,3,4,5,6,7,'A','B','C','D'};

the number 1,2,...,7 should like below

char studentID[12]            = {'S','1','2','3','4','5','6','7','A','B','C','D'};
Andrei Sfat
  • 8,440
  • 5
  • 49
  • 69
harvey
  • 1
  • 1