This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

interrupts messin' with vsprintf ?

I have a 1ms fixed time interrupt scanning and debouncing a couple of switches, and a 1200 baud port receiving blocks of 17 chars 4 times a sec.
Asynchronously at 5 times/sec, I'm assembling an 8 character string to display on an 8 character DM display.
This code now uses a vsprintf statement, and occasionally the output string gets leftshifted one character in the buffer.
Surrounding the vsprintf call by EA=0 and EA=1 solves the problem, but the resulting delay to my fixed time interrupt messes up the switch scan.
Anybody have any clues on why vsprintf is getting upset, and how to get around it?
Thanks in advance.

  • Julian,

    Without knowing the specifics of what interrupts that you are using and how they are set up, this may or may not help. My first guess, based on the fact that the problem only occurs sometimes and disabling interrupts removes the problem, is the timer ISR is being interrupted by another ISR or vice versa. You should be able to eliminate this problem by making sure that the timer that is critical to your switch scan is set to the highest possible priority and that it uses a register bank that is not used by any other ISRs (or at least any ISR that have the same or higher priority) or functions in your code. Also, if the vsprintf() is being called from the ISR, you may want to see if you can come up with a scheme to get this pulled out of there. It uses variable arguements, can be time consuming and could cause a variety of stack and state problems that would not be a problem outside of an ISR. I can come up with some other possibilities if this doesn't help any. If this is the case, please include whether code is SMALL, COMPACT or LARGE, what other interrupts you are using, and if you are using any directives or pragmas that effect function calling such as NOAREGS, MAXARGS set to a small value, etc.

    First time that I have offered my two cents and I hope it is helpful. I have never participated in any discussion forums and I am therefore not familiar with the etiquette or proper protocol of responding. Please let me know if this reply is not appropriate in any way whatsoever.

    Brian

  • Brian,
    Your etiquette is perfect, and your suggestions valid, thank you :-)
    There are only two interrupts. The fixed time interrupt that handles the switches is at the higher priority setting, and the serial interrupt at the lower. They both have separate and unique "using" modifiers. The vsprintf is not in an interrupt, for obvious reasons, but having to disable interrupts while it is running is almost as disasterous to the behavior of the system. Code is SMALL, no pragmas or directives.
    I'm using a Metalink iceMaster-PE emulator. Looking at the internal memory display when I interrupts execution, I see the top 16 bytes up to 0xFF are red, meaning that they got changed recently. This indicates that I've blown the stack. Hmmm ...
    Thanks for the ideas, if you have any more, I'd love to here them.

  • Julian,

    The stack is looking suspect, but if you don't find a problem there, the next thing you could check out is the format strings. In light of the fact you are using vsprintf and not sprintf I am assuming different format strings are being used depending on situation at hand. Is one particular format string causing the drop char problem? Any possibility that there is a type size mismatch between format specifier and arguement being passed in? ( ex. sprintf(szBuff, "%d", by) will muck things up. I got stung with this one a while back.) Using vsprintf doubtfully allows you to cast you arguements, but you can use the optional b,h and l type modifiers in the format strings that you are using or generating to work around this mismatch problem.

    Brian

  • I did check the arg sizing - yes, I've been burned by that before myself.
    Here's what I'm going to do next:-
    I have a classic serial rcv interrupt handler loading a circular buffer, and an async unloader with its own buffer getting info to display. This is using up tons of space, and I only have 17 bytes of stack left.
    As I have a fixed format coming in the serial port, I'll combine the two functions into the interrupt routine, which will save some buffer handling time and a gob of memory, relatively speaking ;-> The interrupt time will go up slightly, but I only get four 17-char blocks every second @ 1200 baud, so I should be OK.
    I've got to get the stack under control, otherwise I don't have a snowball's chance of success.
    Thanks again for your suggestion.

  • You have only 3 tasks: Background, Timer, Serial.

    What are the priority levels of Timer & Serial?

    Is vsprintf is used only in Background?

    Does "string gets leftshifted one character" mean that it is always the 1st character in the buffer is dropped?

    How do you know the character is being dropped? Is it being detected on the receiver end, or do you break on an assertion while using the ICE?

  • Do you interrupt routines call functions that are also called by the main function?

    If so, are you using the NOAREGS directive to ensure that absolute register accesses are not used?

    Do you receive any errors or warnings when you link?

    Jon

  • Three tasks as stated, correct: timer at high priority "using 1"; serial at low priority "using 2", eveything else "using 0" by default.
    Some folk refer to non-interrupt as fg, some as bg. It seems to depend on your point of view or focus at the time! To try to avoid the religious argument, I refer to non-interrupt as "asynchronous" (i.e. to any specific hardware event).
    Anyhow, vsprintf is not called from any interrupt, only from a function called from an infinite loop in main().
    "First character dropped":
    The first character is always a space where a minus sign would be, so I'm not sure if the character is dropped, or whether it is left-shifted. I'll try to find that out. No characters EVER appear to be missing from within the string, however.
    I "know" only because
    a)it appears that way on the 8-char display.
    b) because the protocol decoder never reports a chcksum error.
    Continuing from last night's discussion, at this moment I'm debugging changes I proposed to make to the serial input interrupt handler, where I remove the second buffer and handle the "protocol" in the interrupt, thus getting stack back. I'll report when it's running.
    Thanks for helping !!!

  • "Do you interrupt routines call functions that are also called by the main function?"
    Nope.

    "Do you receive any errors or warnings when you link?"

    Only "L16: Uncalled segment" warning. I'm happy with those, they're uncalled functions.

    Thanks for helping.

  • What happens if you all ways pass the vprintf statement a constant negative number?

    I am still interested in your Timer & Serial interupt priorities. The "using" statement refers to which register bank is associated with the ISR. Priority are set by you. You need to set bits in the IP (interrupt priority register). Sounds like they are at the same level.

    Just acomment on "I'm happy with those, they're uncalled functions."

    This is not quit true. The memory for their local variables though not used, are allocated and not shared by the rest of the program. If you would like more data space for your buffers, I would get rid of them.

  • "What happens if you all ways pass the vprintf statement a constant negative number?"
    I'll find out as soon as I get the new rcv code running. As I said earlier (actually, late last night!) I think I was blowing the stack, so I had to fix that problem first.

    "I am still interested in your Timer & Serial interupt priorities. The "using" statement refers to which register bank is associated with the ISR. Priority are set by you. You need to set bits in the IP (interrupt priority register). Sounds like they are at the same level."

    Understand. A code snippet will help here, I
    think:
    The serial port setup:
    /*------------------------------------------
    Setup serial port registers.
    ------------------------------------------*/
    SM0 = 0; SM1 = 1; /* serial port MODE 1 */
    SM2 = 0;
    REN = 1; /* enable serial receiver */

    TI = 0; /* clear transmit interrupt */
    RI = 0; /* clear receiver interrupt */

    ES = 1; /* enable serial interrupts */
    PS = 0; /* set serial interrupts to low priority */

    and now the fixed time interrupt :-
    TMOD &= ~0x0F; // clear timer 0 mode bits
    TMOD |= 0x01; // set 16-bit no prescale mode

    TL0 = (TIMER0_COUNT & 0x00FF);
    TH0 = (TIMER0_COUNT >> 8);

    PT0 = 1; // set high priority for timer 0
    ET0 = 1; // enable timer 0 interrupt
    TR0 = 1; // start timer 0

    (I omitted the EA=1, but it is in the code.)
    As you can see, the priority bits are taken care of.

    Point taken on the uncalled functions issue.
    I will certainly clean them up shortly. Right now I appear to have enough stack space, and I'm trying to get my new serial decoder working. I have a 17 byte fixed-format string coming in, and I have a checksum error for some reason.
    I'll report again as soon as it's working.
    Many thanks for the help, I appreciate it.

  • "What happens if you all ways pass the vprintf statement a constant negative number?"
    I'll find out as soon as I get the new rcv code running. As I said earlier (actually, late last night!) I think I was blowing the stack, so I had to fix that problem first.

    "I am still interested in your Timer & Serial interupt priorities. The "using" statement refers to which register bank is associated with the ISR. Priority are set by you. You need to set bits in the IP (interrupt priority register). Sounds like they are at the same level."

    Understand. A code snippet will help here, I
    think:
    The serial port setup:
    /*------------------------------------------
    Setup serial port registers.
    ------------------------------------------*/
    SM0 = 0; SM1 = 1; /* serial port MODE 1 */
    SM2 = 0;
    REN = 1; /* enable serial receiver */

    TI = 0; /* clear transmit interrupt */
    RI = 0; /* clear receiver interrupt */

    ES = 1; /* enable serial interrupts */
    PS = 0; /* set serial interrupts to low priority */

    and now the fixed time interrupt :-
    TMOD &= ~0x0F; // clear timer 0 mode bits
    TMOD |= 0x01; // set 16-bit no prescale mode

    TL0 = (TIMER0_COUNT & 0x00FF);
    TH0 = (TIMER0_COUNT >> 8);

    PT0 = 1; // set high priority for timer 0
    ET0 = 1; // enable timer 0 interrupt
    TR0 = 1; // start timer 0

    (I omitted the EA=1, but it is in the code.)
    As you can see, the priority bits are taken care of.

    Point taken on the uncalled functions issue.
    I will certainly clean them up shortly. Right now I appear to have enough stack space, and I'm trying to get my new serial decoder working. I have a 17 byte fixed-format string coming in, and I have a checksum error for some reason.
    I'll report again as soon as it's working.
    Many thanks for the help, I appreciate it.

  • "What happens if you all ways pass the vprintf statement a constant negative number?"
    I'll find out as soon as I get the new rcv code running. As I said earlier (actually, late last night!) I think I was blowing the stack, so I had to fix that problem first.

    "I am still interested in your Timer & Serial interupt priorities. The "using" statement refers to which register bank is associated with the ISR. Priority are set by you. You need to set bits in the IP (interrupt priority register). Sounds like they are at the same level."

    Understand. A code snippet will help here, I
    think:
    The serial port setup:
    /*------------------------------------------
    Setup serial port registers.
    ------------------------------------------*/
    SM0 = 0; SM1 = 1; /* serial port MODE 1 */
    SM2 = 0;
    REN = 1; /* enable serial receiver */

    TI = 0; /* clear transmit interrupt */
    RI = 0; /* clear receiver interrupt */

    ES = 1; /* enable serial interrupts */
    PS = 0; /* set serial interrupts to low priority */

    and now the fixed time interrupt :-
    TMOD &= ~0x0F; // clear timer 0 mode bits
    TMOD |= 0x01; // set 16-bit no prescale mode

    TL0 = (TIMER0_COUNT & 0x00FF);
    TH0 = (TIMER0_COUNT >> 8);

    PT0 = 1; // set high priority for timer 0
    ET0 = 1; // enable timer 0 interrupt
    TR0 = 1; // start timer 0

    (I omitted the EA=1, but it is in the code.)
    As you can see, the priority bits are taken care of.

    Point taken on the uncalled functions issue.
    I will certainly clean them up shortly. Right now I appear to have enough stack space, and I'm trying to get my new serial decoder working. I have a 17 byte fixed-format string coming in, and I have a checksum error for some reason.
    I'll report again as soon as it's working.
    Many thanks for the help, I appreciate it.

  • Sorry about the multiple posts.
    The forum software reported a timeout error, but accepted the post anyway.
    Seems I'm not the only one with bugs ;->

  • Well it helps, if one is accumulating a checksum, to do so BEFORE stripping off the parity bit ...
    More to the point, it seems that getting more stack room solved my problem with vsprintf.
    I've spent all my embedded years on x86 and 68k, where stack space was the least of my problems. This x51 stuff requires a whole different discipline and strategy.

    Many thanks to those who offered help.
    Kudos, too, to Keil for a great optimizing compiler - I guess they take the 'micro' out of 'microcomputer' :-)

    On to the next problem ...