Post Go back to editing

I want to know how to deal with crashes that occur in C language and assembler.

Category: Software
Product Number: ADSP-21565
Software Version: 2.11.0.0

Hi.

I am writing control in C language and filter calculations in assembler for high-speed calculations.
The input consists of two different sampling signals.
Signal acquisition uses DMA interrupts, and calculations use software interrupts. Additionally, I read and write to QSPI memory while outputting signals.
Switching soft interrupts or accessing memory causes a few lines of assembly code to break and crash the system. Alternatively, crashes occur due to issues with return address or jump address.
I understand that I should not use i6/i7/m7, etc., within assembly code, but
    1: What other registers besides MODE1/ASTATX/CMMR0 should be saved within assembly code?
 2: I think there are registers that should be saved during interrupts. Which registers specifically?
        How should this be written in C language? How should MODE1 be written?
        The CMMR SYSCTL can be written as follows:
                ESC_SYSCTL=*pREG_CMMR0_SYSCTL;

Thanks, Regards,

YAMAMOTO

  • Hi Yamamoto,

    Regarding "What other registers besides MODE1/ASTATX/CMMR0 should be saved within assembly code?"
    >>>In any assembly routine—especially interrupt handlers or functions called from C—you must save and restore all callee-saved registers, such as data registers (R4–R7),pointer registers (P3–P5), index and loop registers (I0–I3, L0–L3, B0–B3, M0–M3, LC0, LC1), and status registers like MODE1 and ASTAT.
    You must avoid using compiler-reserved registers such as I6, I7, and M7, as they are reserved for stack frame and return address management by the compiler. These rules are required to maintain system stability and proper C-ASM integration.

    For more details, please refer to the following help path in CCES:
    CrossCore® Embedded Studio 2.11.0 > SHARC® Development Tools Documentation > C/C++ Compiler Manual for SHARC® Processors > Compiler > C/C++ Run-Time Model and Environment > Registers

    Regarding "How should this be written in C language? How should MODE1 be written?"
    >>> Memory-mapped registers, such as CMMR0_SYSCTL, can be accessed directly in C using pointers.
          
    Please find below a code snippet demonstrating how to set and clear specific bits of the MODE1 register using the sysreg_bit_set() and sysreg_bit_clr(),
          
          #include <sysreg.h>
          sysreg_bit_set(sysreg_MODE1,(BITM_REGF_MODE1_SPERREN ));
          sysreg_bit_set(sysreg_MODE1,(BITM_REGF_MODE1_SPERREN ));
          
    Please use this snippet as a reference and modify it accordingly to your application requirement.

    Regards,
    Nandini C

  • Hi. Nandini C-san

    I am writing interrupts from the microcomputer in C language and interrupts from the filter in assembler, but sometimes it crashes.
    When calling assembler from C,
    I understood that I should not use /i6/i7/l6/l7/b6/b7/m5/m6/m7/m13/m14/m15 and that I should return with L set to 0.
    However, are the registers R4-R7, I0-I3, b0-b3, m0-m3, etc., that you mentioned not supposed to be used within the assembler?
    Do I need to restore their original values when returning from the assembler to C?
    Additionally, I understand that I can manipulate bits like MODE1, but how should I describe copying MODE1, 2, and ASTATX directly into the registers when saving them?
    I understand that SYSCTL should be written like this.
    RES_SYSCTL=*pREG_CMMR0_SYSCTL;

    Thanks, Best Regards,

    YAMAMOTO

  • Hi,

    Regarding "I understood that I should not use /i6/i7/l6/l7/b6/b7/m5/m6/m7/m13/m14/m15 and that I should return with L set to 0.
    However, are the registers R4-R7, I0-I3, b0-b3, m0-m3, etc., that you mentioned not supposed to be used within the assembler?
    >>>You can use R4–R7, I0–I3, B0–B3, M0–M3 in assembler.But only if you save and restore them when your assembly code is called from C.
    These status registers cannot be pushed directly onto the stack, so you must first move their contents into general-purpose registers (like R0), and then store those to memory.

    Regarding "Do I need to restore their original values when returning from the assembler to C?"
    >>>Yes.

    Regarding "how should I describe copying MODE1, 2, and ASTATX directly into the registers when saving them?"
    >>> If you are copying this MODE1, MODE2, and ASTATX status registers in assembly, you need to use data registers (such as R0, R1, R2, etc.) as intermediates. These status registers cannot be pushed directly onto the stack, so you must first copy their values into general-purpose registers, then store those registers to memory.

    Regarding "I understand that SYSCTL should be written like this."
    >>>Are you asking about restoring the register values in C or in assembly?

    Regards,
    Nandini C

  • Hi. Nandani C-san

    When calling assembler from C,
    if R4-R7, I0-I3, b0-b3, and m0-m3
    cannot be used, should I use the secondary DAG?
    Is it necessary to push LCNTR?
    Please tell me how to load MODE1/ASTAT into memory in C.
    Currently,
    there are cases where the secondary DAG cannot be set in an assembler program that filters interrupts from an MCU written in C language.
    The current situation is that the interrupt handling program written in C language and the filter program written in assembler frequently crash due to some malfunction.

    It worked well with SHARC, but I am struggling with SHARC+.

    Regards,

    YAMAMOTO

  • Hi,

    Regarding "When calling assembler from C, if R4-R7, I0-I3, b0-b3, and m0-m3 cannot be used, should I use the secondary DAG?"
    >>>If R4–R7, I0–I3, B0–B3, and M0–M3 cannot be used due to the C calling convention, you should use the secondary DAG registers instead.
    Please refer the Alternate (Secondary) DAG Registers section [Pg.No:214/798] in the ADSP-215xx Programming Reference Manual. Please find the below link,
    www.analog.com/.../sc58x-2158x-prm.pdf

    Regarding "Is it necessary to push LCNTR?"
    >>>You do not have to save/restore LCNTR as hardware loop controller manages loop stack automatically, but if your asm code switches DAG/register sets, calls C functions or has nested interrupts then the loop stack and program stack could get out of sync unless you explicitly save LCNTR.
    For such scenarios, push LCNTR at the start and restore it before returning.

    Regarding "Please tell me how to load MODE1/ASTAT into memory in C."
    >>>Please find the below snippet:

    asm volatile("%0 = MODE1;" : "=d"(mode1_backup)); // Copy MODE1 into variable

    Regards,
    Nandini C

  • Hi, Nandini C-san

    The push for MODE1/ASTAT that you taught me
    asm volatile(“%0 = MODE1;”:“=d”(mode1_backup));
    put the MODE1 data into mode1_backup.
    How do I write the reverse?
    How should I describe ASTATX?
    Also, in which manual is it written that I should write %0 = MODE1; or “=d”(mode1_backup)?

    Thanks & Regards,

    YAMAMOTO

  • Hi Yamamoto,

    Regarding "How do I write the reverse?"
    >>>Please find the below snippet for reference.

    uint32_t mode1_backup;
    asm volatile("%0 = MODE1;" : "=d"(mode1_backup)); //MODE1 register into mode1_backup
    mode1_backup |= (1U << 5);
    asm volatile("MODE1 = %0;" :: "d"(mode1_backup)); // Write modified value back to MODE1

    Regarding "How should I describe ASTATX?"
    >>> Are you asking about to read/write this register. If so,you can use the above format for ASTATX as well.

    Regarding "Also, in which manual is it written that I should write %0 = MODE1; or “=d”(mode1_backup)?"
    >>> Could you please find the asm() Construct Syntax[Page No:158/486] in the CCES Sharc complier manual.Please find the below link,
    https://www.analog.com/media/en/dsp-documentation/software-manuals/cces-sharccompiler-manual.pdf

    Regards,
    Nandini C

  • Hi. Nandini C-san

    Thanks. 

    When writing to the QUAD I/O memory while an interrupt signal is active,
    the function waiting for the external memory response in SPI_Functions.c fails to receive the response and hangs. (Code below)
      while(!(*pREG_SPI2_STAT & BITM_SPI_STAT_TF)); // wait till completion
    I need to output signals even while memory is being written.
    Is there any way to prevent this from hanging?

    Thanks, Best Regards,

    YAMAMOTO

  • Hi,

    Apologies for the delayed response.

    While waiting for the transfer complete bit (BITM_SPI_STAT_TF), this line (while(!(*pREG_SPI2_STAT & BITM_SPI_STAT_TF)); queries the SPI status register continually.

    We recommend using the DMA controller of the ADSP-21565 for your application. DMA fully offloads the task from the processor core by enabling the SPI peripheral to manage data transfers on its own. By doing this, the busy-wait loop is avoided, allowing the system to continue handling your output signals and interrupts without experiencing any performance problems.
    As an alternative to busy-waiting, you can use interrupt-driven SPI transfers. When the transfer is finished, you can set up the SPI peripheral to cause an interrupt. As a result, the system can continue other tasks while the SPI transfer is underway, and an Interrupt Service Routine (ISR) effectively handles the transfer completion.

    Regards,
    Nandini C

  • Nandini C -san

    Thank you.
    When I hear “DMA,” I imagine moving data from one address to another,
    but I can't visualize how the data moves within the SPI status register.
    Also,
    the provided program is SPI_Function.c,
    but I don't know how to modify it.
    Please provide a concrete program that reads from and writes to the QSPI memory.

    Best regards,

    YAMAMOTO