Understanding correct ISR implementation

I'm using some ISRs for timers and for reconfiguring the DMAC after copying a block of ADC data to external memory.

While reading about another topic on this forum I noticed various mentions of





However, I also saw various Synergy examples which don't use these. My current understanding is as follows:

SF_CONTEXT_SAVE and SF_CONTEXT_RESTORE are mainly used to enable ISR event tracing with TraceX. It shouldn't really matter if these are missing with the current implementation when this feature is not needed.

R_BSP_IrqStatusClear(R_SSP_CurrentIrqGet()); is used to clear the ISR flag of the current ISR to prevent calling it twice when it doesn't finish fast enough.

I also saw a mention that some peripherals might need some flags cleared in their ISRs (e.g. here: renesasrulz.com/.../interrupts-under-threadx https://renesasrulz.com/synergy/f/synergy---forum/7254/making-own-isr-in-s7g2 ). How can I find out what I need to clear? I don't clear anything right now.

  • In reply to Richard:

    Hi Richard,
    could you explain this line:
    R_DMAC0->DMCRA = 0x00040004;

    In my understanding only the block number needs to be reset. In R_DMAC_Reset there is
    if ((TRANSFER_MODE_NORMAL != HW_DMAC_ModeGet(p_dmac_regs)))
    HW_DMAC_BlockNumberSet(p_dmac_regs, num_transfers);
    HW_DMAC_TransferNumberSet(p_dmac_regs, num_transfers);

    so here only HW_DMAC_BlockNumberSet(p_dmac_regs, num_transfers); would be called.
  • In reply to ChrisS:

    I assume you are referring to this part of the code:

    /* Reset the DMAC for the next capture
    * Not using the api g_adc_transfer1.p_api->blockReset as that automatically enables the DMA
    * This is not required as the other DMAC interrupt will do this
    * Therefore, reinitialise manually
    R_DMAC0->DMDAR = (uint32_t)&adc0_result_buffer[ dmac0_buffer_full_counter * 10000L ];
    R_DMAC0->DMCRA = 0x00040004;
    R_DMAC0->DMCRB = 2500;

    If so, the reason is a bit of lazy cut and pasting from a previous project!

    You are correct. Once the DMAC has been set up for block mode transfer the DMCRA.H is constant (block size) and DMCRA.L (block size counter) is decremented and automatically initialised when it equals 0, so it's only the DMCRB (the DMA Block Transfer Count Register) that needs reinitialising.
    You can remove it.
  • In reply to Richard:

    I had some issues getting my version to run but I solved them and the first results look promising.
    I'm using one callback for both DMACs and so I use the enable/disable functions as they control the interrupt as well.
    We will do more extensive tests on Monday.
  • In reply to ChrisS:

    Keep me posted. If your implementation has issues then I have another version, that uses a timer to count the number of DMA transfers and via a timer ISR, keeps the DMCRB from reaching 0. Therefore, the DMA can run continuously.
    This may want to look at this too?
  • In reply to Richard:

    That also sounds like an interesting approach, I didn't know that it was possible to set the registers while running. Is it possible to guarantee a deterministic stopping behaviour with that method? I need to be able to save the whole ring buffer.
  • In reply to ChrisS:

    I have uploaded my project (S7G2_DK_ADC_DMAC_CONTINUOUS.zip) to the media gallery.
    The project captures ADC data to the SDRAM buffer in 1second packets ( 2000000 ADC data values )

    The mechanism is as such:
    (Project written for the S7G2-DK board, as this is the only board I have with SDRAM fitted)

    S1 (user push button) generates IRQ11. IRQ11 ISR (callback) starts GPT2 running

    GPT2 starts GPT1 and 1 second later, GPT2 stops GPT1. GPT2 will also stop itself.

    When running, GPT1 triggers the ADC every 2us

    ADC performs a conversion on AN000, AN001, AN002 & AN003

    ADC conversion end event triggers DMAC0

    DMAC0 performs a block transfer of AN000, AN001, AN002 & AN003 to SDRAM. DMAC0 block transfer counter (DMCRB) is decremented by 1. If DMCRB = 0, the DMAC will stop and will not perform further transfers until it is re-enabled.
    The starting count value of DMCRB = 65535;

    ADC conversion end event also increments the counter of GPT0.

    GPT0 is configured to overflow at 65530 and generate an interrupt on overflow.
    At overflow, the DMRCB = 5, very close to reaching 0 and stopping the DMAC.

    The GPT0 overflow ISR resets the DMRCB back to 65535.
    Therefore, the DMAC never stops as DMRCB never reaches 0.

    This mechanism allows for 2000000 ADC samples to be captured by the DMA continuously.

    To answer your question
    "I didn't know that it was possible to set the registers while running. Is it possible to guarantee a deterministic stopping behaviour with that method? I need to be able to save the whole ring buffer."

    The DMA has the ACT status flag, which is set when a transfer is tacking place, and clear when not.
    The User's Manual has the restriction on register access:

    Do not write to the following registers of DMACm while the ACT flag in DMSTS of the associated channel is set to 1 (DMAC active state) or the DTE bit in DMCNT of the associated channel is set to 1 (DMA transfer enabled):

    Therefore, in the GPT0 ISR that rewrites the DMCRB, the mechanism is:

    while(R_DMAC0->DMSTS_b.ACT == 1); /* Wait for the DMA to be idle */

    R_DMAC0->DMCNT_b.DTE = 0; /* Disable DMAC */
    R_DMAC0->DMCNT_b.DTE = 1; /* Enable DMAC */

    As mentioned, the project uses a GPT timer to generate an accurate 1 second window. Via the Compare Match A & B events, and the ELC, GPT1 (and the ADC / DMAC ) can be controlled in an accurate manor.
    To ensure that I'm not getting any ADC error readings, I do some simple data processing to ensure that there are no ADC results above or below a threshold. My tests indicate that this is the case.

    This approach may be of interest.
    I hope that with this project and with the previous ones that we have discussed you are able to get your application working as required.
    Any issues, let me know