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

P89LPC932 and serial communication, strange phenomenon

Following set:
Two identical PCBs (my hardware design using the LPC932), one with the "real" MCU, other with connector adaptor to EPM900 board.
My software runs smooth on the emulator. I always send 24 bytes via COM5 (virtual COM port of FTDI232 USB-to-RS232 chip). The MCU processes the 24 bytes, executes a command, some routines and sends 24 bytes back to PC.
The 24 bytes are a certain telegram with a two byte header and a checksum at the end.
So far, so good. As I said, it runs smooth on the emu.
But when I flash the compiled hex file into the LPC932 on the other board and connect this board with USB (COM5), I can send the 24 bytes to COM5, but I receive an error code generated by my firmware telling me the header is wrong.
I found out that the last, the 24th byte, is somehow coming to the first position of the serial input buffer. Example:
PC sends: AA 55 00 FF .... FF 60
hardware should have: AA 55 00 FF ... FF 60
in the 24 byte input buffer, but it has: 60 AA 55 00 FF ... FF
No idea. Code is fine, I worked it out a thousand time. The whole buffer seems to be shifted. I repeat, this runs correct on the emu, which holds the same MCU.

The worst fact is, that sometimes the code in the "real" MCU runs correctly after being connected to supply voltage (USB), sometimes it doesn't. So the code must be ok.

Any clue?

Thanks for any help.

Parents
  • "sometimes the code in the "real" MCU runs correctly after being connected to supply voltage (USB), sometimes it doesn't. So the code must be ok." (my emphasis)

    How on earth do you reach that conclusion?!

    If the system only "sometimes" works, then it can't be "OK", can it?!

    This could be a hardware fault, or a software fault, or both!

    Software faults that could cause this sort of behaviour include uninitialised variables (especially uninitialised pointers), data corruption (eg, due to bad pointers or bad overlaying), and faulty interrupt service routines.

    Uninitialised variables would be a prime suspect when code works in a simulator and/or emulator, but not in a real target...

    If you are using software timing functions, these could cause you all sorts of grief if they aren't quite right...

Reply
  • "sometimes the code in the "real" MCU runs correctly after being connected to supply voltage (USB), sometimes it doesn't. So the code must be ok." (my emphasis)

    How on earth do you reach that conclusion?!

    If the system only "sometimes" works, then it can't be "OK", can it?!

    This could be a hardware fault, or a software fault, or both!

    Software faults that could cause this sort of behaviour include uninitialised variables (especially uninitialised pointers), data corruption (eg, due to bad pointers or bad overlaying), and faulty interrupt service routines.

    Uninitialised variables would be a prime suspect when code works in a simulator and/or emulator, but not in a real target...

    If you are using software timing functions, these could cause you all sorts of grief if they aren't quite right...

Children
  • "sometimes the code in the "real" MCU runs correctly after being connected to supply voltage (USB), sometimes it doesn't. So the code must be ok." (my emphasis)
    How on earth do you reach that conclusion?!


    How? A code in a flash ROM can't sometimes run ok and sometimes not. The environment of the processors MUST not effect the execution of code. Only if a port is read and bits are influenced by connected hardware or HF. Even if the internal code execution is affected by any external influence it won't behave permanently equal (several read's and write's bring always the same result)

    Software faults that could cause this sort of behaviour include uninitialised variables (especially uninitialised pointers), data corruption (eg, due to bad pointers or bad overlaying), and faulty interrupt service routines.
    Pointers don't need to be initialised, they only need to be set. My input buffer is a structure which is cleared with zeros at start and is cleared again after each reception of 24 bytes. This is my ISR:

    void serint (void) interrupt 4
    {
    KB3 = 1;
    error = 0;
    char_ptr1 = &iobuf;
    char_ptr1 += rxcount;
    *char_ptr1 = SBUF; // copy byte by byte to receive buffer
    RI = 0; // clear RI flag
    rxcount++;
    if (rxcount == 24) // after 24 bytes received progress and
    { // do some checking
    if (iobuf.header != 0xAA55) error = 3; // check if header is correct
    //calc_incheck(); // calc checksum and compare
    if (!error)
    {
    if (values.idnumber == iobuf.idnumber) rxflag = 1;
    else rxflag = 0;
    if (iobuf.idnumber == 0)
    {
    if (iobuf.command == 0xff) rxflag = 1;
    if (iobuf.command == 0xef) rxflag = 1;
    if (iobuf.command == 0x9f) rxflag = 1;
    }
    }
    rxcount = 0;
    }
    }

    rxcount is set to 0 at the start:
    // START
    KB3 = 0;
    EA = 1; // enable interrupts
    ESPI = 1; // enable SPI interrupt
    init_adc(0xA000); // initialize the ADC (needed for start after power up
    delay(100);
    init_adc(0xA800); // configure ADC (mode 00, CS starts, short sample)
    P2 &= 0x3F; // Standby/Remote off
    clear_iobuf(); // clear buffer
    rxcount = 0; // clear some var's
    error = 0;
    rxflag = 0;
    /* Main loop */
    ESR = 1; // enable serial interrupt
    REN = 1; // enable serial reception
    while (1)
    {
    if (error != 0)
    .
    .
    This is part of the main function where the variables and register are set.

    The "behaviour" of the internal RAM is silly. If I put the structure to IDATA or DATA, it works quite correct (with the error described above). If I use the directive XDATA to put it into XRAM, the code sends total crap.
    And this is the only variable/structure in XRAM. So no overlap can occur. In this case the compiler would warn me, anyway. The emulator holds the same MCU (EPM900) as my target hardware. The code is loaded into the external memory of that MCU. This is the only difference. It does not run from the internal flash ROM.

  • The "behaviour" of the internal RAM is silly. If I put the structure to IDATA or DATA, it works quite correct (with the error described above). If I use the directive XDATA to put it into XRAM, the code sends total crap.

    That nugget alone is already a very strong hint that your problem is indeed caused by uninitialized variables or lack of volatile qualifiers on variables shared by concurrent threads of execution. Reset state of XRAM may very well be less deterministic than that of RAM cells internal to the chip. Lack of 'volatile' qualifiers causes randomized failurs, but will get worse if the volatile variables are in XRAM, where acces is slower, and thus the probability for a task switch at an unlucky moment rises.

    I.e. you should consider the rather realistic possibility that your code worked on the emulator only by luck (details of its reset behaviour and power supply), rather than by design.

  • That nugget alone is already a very strong hint that your problem is indeed caused by uninitialized variables or lack of volatile qualifiers on variables shared by concurrent threads of execution. Reset state of XRAM may very well be less deterministic than that of RAM cells internal to the chip.
    Ja, aber welche Variablen? Ich benutze fĂĽr die DatenĂĽbertragung die Variable rxcount, das Flag rxflag, die Struktur iobuf und den Pointer char_ptr1. Alles sauber deklariert im Sub-File var.c und var.h.
    Die Daten kommen auch recht sauber und richtig an RxD an, mit Oszi nachgemessen.
    XRAM ist ĂĽbrigens intern beim LPC932. Das X steht fĂĽr auxiliary. Deswegen auch XDATA.
    Und wenn der Code dort eine Struktur aufbaut, die anschlieĂźend beim Boot-up mit Nullen ĂĽberschrieben wird, wo soll da was nicht richtig gesetzt oder initialisiert sein?
    Meine Vermutung geht dahin, daß der Keil-Compiler da was nicht richtig macht. Aber bei den vielen Möglichkeiten nehme ich entweder das, was mir am sinnvollsten erscheint oder die default-Einstellungen. Die sollten für das Target LCP932 eigentlich immer passen.
    Leider paßt weder das Memorymodel SMALL noch das LARGE genau auf den Prozessor. Aber ich muß SMALL nehmen, weil bei COMPACT und LARGE der Code >4k wird und da schlägt die 4k-Code-Begrenzung des Compilers zu.

  • So no variable could "come up 0 or FF". I didn't speak about 0s or FFs, I spoke about the last byte of the transmission somehow wanders at the first byte of the input buffer.
    If you write buffer[offset & ...] as is usually done the difference between 0 and ff would EXACTLY show the phenomen you describe.

    Und wenn der Code dort eine Struktur aufbaut, die anschlieĂźend beim Boot-up mit Nullen ĂĽberschrieben wird, wo soll da was nicht richtig gesetzt oder initialisiert sein?
    only if startup.a51 match your actual situation

    Erik

  • How? A code in a flash ROM can't sometimes run ok and sometimes not
    About 90% of my short time consultings have been to prove that statement wrong.

    Erik

  • So no variable could "come up 0 or FF". I didn't speak about 0s or FFs, I spoke about the last byte of the transmission somehow wanders at the first byte of the input buffer.
    If you write buffer[offset & ...] as is usually done the difference between 0 and ff would EXACTLY show the phenomen you describe.

    I'm not completely sure if I got you correct.
    As you can see in the code example above, it writes to buffer using a pointer. With the first byte coming in from the UART, the pointer is set to the beginning of the I/O buffer structure, the byte is written into it and the byte counter is incremented. Next round the pointer points to the second byte in the I/O buffer and so on. After 24 bytes the byte counter and thus the pointer are reset with the next byte coming in.

    Und wenn der Code dort eine Struktur aufbaut, die anschlieĂźend beim Boot-up mit Nullen ĂĽberschrieben wird, wo soll da was nicht richtig gesetzt oder initialisiert sein? only if startup.a51 match your actual situation.
    As I told before, I have a function which clears the I/O buffer with zeros at startup and after every 24 bytes received.

  • As you can see in the code example above
    unreadable because you did not use pre and /pre
    also, there is no indication what is int and what is char. Int used in both an ISR and main is one of the most "popular" causes of "this proven well working program fails, it can not be my code"

    As I told before, I have a function which clears the I/O buffer with zeros at startup
    What does that achieve if the pointer is wrong when the first char is written.

    Erik

  • As you can see in the code example above
    unreadable because you did not use pre and /pre
    also, there is no indication what is int and what is char. Int used in both an ISR and main is one of the most "popular" causes of "this proven well working program fails, it can not be my code"

    As I told before, I have a function which clears the I/O buffer with zeros at startup
    What does that achieve if the pointer is wrong when the first char is written.

    Erik

  • [I'll answer in English, for the benefit of the other readers here who don't know any German]


    Ja, aber welche Variablen?

    Those variables used by both the IRQ handler and the main routine, to communicated with each other. These must be declared volatile, or what you've observed is only the beginning of the strange behaviour you'll experience.

    Und wenn der Code dort eine Struktur aufbaut, die anschlieĂźend beim Boot-up mit Nullen ĂĽberschrieben wird

    How certain are you that this actually is initialized to zeros? Did you check that, in a debugger session?

    Meine Vermutung geht dahin, daĂź der Keil-Compiler da was nicht richtig macht.

    I don't think you have shown anywhere near conclusive data to draw any such conclusion.

    4k-Code-Begrenzung des Compilers

    That limitation only exists in the, well, "limited" editions of the compiler. If you're really going to work with this stuff, do yourself a favour and get a full version.

  • Sorry, Erik, I don't use this forum very much so I didn't remember that 'pre' thingy. But the code should be readable even on green. ;O)

    About the pointer: I'm not as stupid as I may sound, but when I set a pointer to a certain address BEFORE I write a byte into this address, the pointer can't be wrong.

    We don't speak about a mysterious device with commonly unexpected and unlogical behaviour, we speak about a microcontroller. It has to work, else it's not worth the money.

  • Ok, let's continue in English.

    Those variables used by both the IRQ handler and the main routine, to communicated with each other. These must be declared volatile, or what you've observed is only the beginning of the strange behaviour you'll experience.

    Oh! This is finally something I can use. My variables are currently global. Whether static nor volatile. In case STATIC isn't used, I assume the compiler will generate a static variable like an Assembler would do. A fixed memory address for every variable. If it isn't so, where should I know how the compiler is working? I'll try this out...

  • I notice that you are taking a rather naive approach to handling your messages. What happens if there is a glitch on the communication line? I would recommend that you do some synchronization to assure that messages are valid and properly framed.

    This might include validating the header bytes as you receive the message, checking for time-outs on partial messages, etc.

  • Oh! This is finally something I can use. My variables are currently global. Whether static nor volatile. In case STATIC isn't used, I assume the compiler will generate a static variable like an Assembler would do. A fixed memory address for every variable. If it isn't so, where should I know how the compiler is working? I'll try this out...
    static oe not makes no difference for global variables. What you have to take care of is ints that are used in both an ISR and main(). If you read these in main() with interrupts enabled, you will get sporadic failures.

    One more thing: re. "it works on the dev. board, not on my board"
    is EVERYTHING identical, I doubt it, list even subtle differences.

    Erik

  • Oh! This is finally something I can use. My variables are currently global. Whether static nor volatile. In case STATIC isn't used, I assume the compiler will generate a static variable like an Assembler would do. A fixed memory address for every variable. If it isn't so, where should I know how the compiler is working? I'll try this out...
    static oe not makes no difference for global variables. What you have to take care of is ints that are used in both an ISR and main(). If you read these in main() with interrupts enabled, you will get sporadic failures.

    One more thing: re. "it works on the dev. board, not on my board"
    is EVERYTHING identical, I doubt it, list even subtle differences.

    Erik

  • Suggest a review of startup.a51 and/or init.a51 for clearing or initializing XDATA.
    Bradford