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

speed up the code

Hallo,
would be nice if someone could take a look on my code.
It's just a little toy to delay an analog signal.

How can i optimize the speed?

unsigned short int Buff[3200];
//*****************************************************
int main (void)
{
   *
   *
   *
   *
}
//*****************************************************
void FIQ_Handler()__fiq __ram       // Timer 1 => Fast Interrupt
{
  static unsigned int position;
  T1CLRI = 0;// Clear Timer1 Interrupt

  DAC0DAT = Buff[position] << 16;   // read from ring_buffer
  while (!ADCSTA){}                 // wait for AD conversion
  Buff[position] = ADCDAT >> 16;    // write to ring_buffer
  ADCCON = 0x6A3;                   // start a new AD conversation
  if (++position >= Buffer_length) position = 0;
}
//*****************************************************

I tested the speed of the code by doing some port-toggling and then oszilloscoping.
Unfortunately software seems to be the limiting element.

Should i use a pointer instead of the variable position?
But as i'am a relative beginner in C i tried but it didn't works in the wanted way :-(

Should i try to write the interrupt-routine in assembler?
Does anybody would like to give me some big hint?
I have no idea how to place the assembler routine inside the IRQ routine.

How can i tell the assembler routine where the Buff[3200] array is located?
How can i tell the assambler routine where the variable Buffer_length is located?

:-)

  • instead of waiting in the interrupt to finish ADC to convert, you should definitely make an interrupt on ADC conversion itself! You can initialize the ADC to use a timer and after conversion you raise your FIQ.
    (At to moment, you have your FIQ on timer interrupt and make the conversion in the FIQ itself - that is a bad design concept)

    Other little optimization possibilities: instead of shifting the values in the interrupt by 16, you can do this outside the interrupt so that in the table, already the shifted values are placed... this shortens the interrupt also for probably 50ns.

  • Thanks for quick reply.
    But as i described the limiting element is not waiting for end of conversation but the code itself.
    To tell the truth code never has to wait for end of conversation, the 12-bit AD-Converter is promoted to run with 1 MSPS.

    I used some port-toggling to oszilloscope timing.

    The reason why i use an Timer Interrupt is that there a several things to to in a main programm.

    My little toy is provided to be a versatile Delay-box.
    The delay time should be variable from a few us to several hours.

    The ARM7 can do shift-operations inside each instruction, so no extra time is wasted.

    I used the __ram statement to speed up a little.

    Are there different methods than port-toggling and oszilloscoping to explore the timing behavior?

  • Note that even if the conversion is done immediately, the test code do represent extra time - the compiler doesn't even know if the condition is expected to be often true or often false.

    Direct addressing using a pointer could improve the speed.

    Does the chip have any DMA capabilities that may be used?

    Have you simulated the interrupt and looked at the clock counter?

  • Hi,
    thanks for your gentle reply.

    You said.
    Direct addressing using a pointer could improve the speed

    Unfortunately and ashamed i must confess that i'am not so familiar with the pointer concept. Of cource i used some pointer to tell a function where to place something.

    void int_to_char(unsigned int X,unsigned char *Anz)
    


    But sorry, no idea how to do adress an array.
    How to decide if pointer has reached the max-position and than reset pointer to first position of array.

  • enum {
        ARRAY_SIZE = 1000
    };
    short array[ARRAY_SIZE];
    short *position = array;
    short *end = array + ARRAY_SIZE;
    
    ...
    
    x = *position;
    *position = y;
    // ALT1
    if (++position >= end) position = array;
    // ALT2
    if (++position >= array + ARRAY_SIZE) position = array;
    // ALT3
    if (++position >= &array[ARRAY_SIZE]) position = array;
    

    ALT2 and ALT3 doesn't require the end variable, which should be better for many processors by replacing a random memory access with the sequential access of the code memory.

  • Peter,
    If you make sure your buffer has the size of a power of 2 (2, 4, 8, 16, 32... bytes) then you can replace the following line

    if (++position >= Buffer_length) position = 0;
    


    with this one

    position &= 0x3FF ;
    


    (if the size you chose for the buffer is say, 1024 bytes)
    Note that the mask will make your position overflows correctly.

    Tamir

  • @ Per Westermark

    Thank you very much for your patience with my ignorance. I think now i will get it :-)

    One additional question:
    What's the reason for this enumerated type?

    enum {
        ARRAY_SIZE = 1000
    };
    


    Does enumerated type make sence with only one member?
    Or is it a very special trick?

    Best regards

  • Yes, is does.

    "Or is it a very special trick?"

    No, it's quite a common technique:

    It's similar to a #define, except that it is handled by the compiler, not the preprocessor.

    Therefore the compiler knows the name of the symbol, and the debugger may also be able to make use of it...

    c-faq.com/.../enumvsdefine.html
    c-faq.com/.../enumprint.html

  • I very much prefer enumerators than #defines for specifying sizes etc.

    An enumerator survives the preprocesor, a #define doesn't. In some situations it may be an idea to just use a const int instead.