Interrupt weird behaviour (perhaps it's PORTD output?)

Go To Last Post
7 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've been working on a project, but have had a recent lack of progress.

I have a Futurlec Mega32 controller board, with onboard DS1307 RTC and a buzzer attached to PORT D.

My project needs to run a 7-segment display of the time, hours/mins/secs. At certain second displays (50, 55, 56, 57, 58, and 59) I need it to make a certain beep noise. At the 00 second display I need it to make a different sound.

I am yet to interface the futurlec controller board outputs to the full clock display, but have connected 8 LEDs to PORT A. I've had I2C working fine for some time, RTC reads work fine. I have a program that reliably reads the time in a constant loop and outputs the seconds onto the PORT A LEDs. I have also set up the output of the DS1307 to generate a 1hz cycle that is used as an external interrupt on interrupt0. I have another program, same basics, that uses a very simple interrupt handler to set a VOLATILE variable, and in MAIN checks that flag and when set it will read the time from the DS1307. This also works reliably.

So now I am trying to add the sounds to the program. In an earlier post, I was contemplating PWM and timers, but had not too much luck getting it to work - I've got no idea about the fault, and lost interest in debugging it further - so I went back to basics and was trying to use in-line tone generation using a FOR loop, but I have a lock-up problem.

If anyone is interested, here's my earlier PWM post: https://www.avrfreaks.net/index.p...

In pseudo-code, the relevant part of MAIN is:

while (forever)
{
  If Time_tick
  {
    clear time_tick
    ds1307_read
    set time_changed
    display secs, PORTA
  }
  if time_changed
  {
    reset time_changed
    if seconds = 0 
       make sound1
    else if seconds =50/55/56/57/58/59
       make sound2
  }
}

... which I hope makes sense.

Problem is: if in the "make a sound" step I use the same code I've used before (which is a subroutine that simply a FOR loop that runs a number of times to toggle a pin on and off with a certain pause between actions) then as soon as the time hits 50 seconds, the whole thing stops.... no tone generated, and no changing time. If I reset the board, the initialisation finishes and the RTC continues on it's way nicely, displaying it's seconds, until it hits 50 again, when it locks up.

I thought that I'd try to simplify things even more, so I reduced the FOR loop to an unsigned char and under 100 loops, but same story. I moved the FOR loop back to inline with MAIN but still the same, as soon as the 50 display came up, things locked up.

So I removed the looping and simply toggled the buzzer on and off once, and, lo and behold, the display continues to run past 50 and a small blip is heard on the buzzer. Yay, a minor breakthrough, but now to figure out why the looping doesn't work.

A cutdown version of my code is attached as a.txt- I've removed the DS1307 sections, as I don't believe it is causing a problem (it works fine when I don't try to make the sound, and for the other 49 seconds).

I'm very much a noob at this stuff, so perhaps it's something obvious that I'm missing, I hope not though!

Can anyone shed any light on this fault? Could be something to do with stack/variables? I'm so lost on this one I'm about to throw the whole kit and project out the window!

If anyone has any thoughts at all, or if there's additional info I should provide to assist understanding/debugging, please let me know !

Dejectedly yours
Brett

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So you wiggle the 0x10 pin to make a sound? You sure you dont need to make 2 pins go lo hi opposite to make the sound? like 0b0001 0000 to 0b0010 0000 (2 pins changing)

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
now to figure out why the looping doesn't work

Your delay loop (inline assembly) macro lists the loop counter only as an
input operand, so the compiler assumes you aren't modifying it -- but you
are, so the second delay loop counts down from 0->0 in 32 bits (~ 30 minutes
rather than 125us).

The loop counter should be listed as both an input and an output operand.
This would look something like (untested):

: "=w" (number_of_loops)   /* output */
: "0" (number_of_loops)    /* input */

where the "0" refers back to operand 0 (the output operand). But check my work.

Edit: Left out the '=' the first time.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

thanks guys for your assistance, much appreciated.

Bob, yes I just wiggle one pin and the sound is generated on the buzzer. It's the way the board I'm using works, and while the buzzer really is meant to simply be turned on, left for a time, then turned off, I can get two acceptable but different sounds out of it without extra hardware by toggling it this way.

Mckenney, I am not sure I fully understand the problem you note with the inline macro....I re-used the code from somewhere else (ie I didn't write it ;)) so perhaps don't understand what it's doing or meant to do as well as I should.

But back to your description of why the problem may be occurring. Is what you're pointing out that if I use the macro twice the compiler doesn't alter the code or handle the changed delay correctly? Sure, thats possible. I would have thought that in the past when I was writing code to test the frequencies I would have come across this problem, but perhaps since I wrapped the calls to the delay inside another function it was handled differently.

So would an acceptable test of this be to have two separate macros that do similar things called in two places? I don't know enough assembler to check your work, so perhaps this is a safer test ? ;)

Actually, just tested that - created a second set of macros for the delays and calculations, and used one call to the original and one to the new. Problem still seems evident. I'm going to let the app run to see if the ~30 minute thing happens.....

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
if I use the macro twice the compiler doesn't ... handle the changed delay correctly?

Since the macro tells the compiler that its argument is a constant (which
it isn't), the second delay doesn't reload the value, so the argument starts
where the previous delay left it, namely a 32-bit 0. The compiler may or may
not decide to do this, depending on context, but in your program (with -Os)
it was doing it.

The simplest/safest test would be to make the change I suggested to your
macro and see if it improves things. In the meantime, I ran the change through
the compiler and it had the intended effect on the assembly code; you'll have
to be the one to try it in your setup.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Is this exactly what you meant? ? .......

#define DELAY_L_ACCURATE(x)  ({ unsigned long number_of_loops=(unsigned long)x;   \
 __asm__ volatile ( "L_%=: \n\t"                   \
 "subi %A0,lo8(-(-1)) \n\t"     \
 "sbci %B0,hi8(-(-1)) \n\t"     \
 "sbci %C0,hlo8(-(-1)) \n\t"    \
 "sbci %D0,hhi8(-(-1)) \n\t"    \
 "brne L_%= \n\t"               \
 : "=w" (number_of_loops)		  \
 : "0" (number_of_loops)        \
 );                               \
 })

I'll give it a whirl when I get back to the dev board, thanks !

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Bewdy mate, that did the job ! Love your work !!!