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

external memory write time

Hello,

I'm trying to move memory from the ADC result result (ADDAT) to external memory (on BUSCON3) ASAP. I'm using the C167HSE Phycore module. From the data sheet for the external RAM, it says that it can write within 10ns, although it didn't specify how many bytes within that 10ns time frame. The fastest result I can achieve for writing from ADDAT to external memory is 10us using xmemcpy, which was verified through the oscilloscope. I even tried to move the data w/o using xmemcpy but the result is still the same. I also tried to tweak the BUSCON3 settings in .a66 file but still no luck. Does anyone have any ideas? Thanks in advance.

Shane

Parents
  • Assuming you are running at 40MHz then the fastest bus cycle is two clocks (50nsec). The fastest bus would be 16-bit demultiplexed. You didn't say what the size of the RAM is but I would suggest remapping /CS3 into segment zero and then using the PEC for the move. This is the fastest way to move data (the MOV instruction is injected in the pipeline upon the ADC interrupt, this also assumes the RAM is 16-bit wide).

    Let me know if you need an example or if this doesn't make sense to you.


    -Chris

Reply
  • Assuming you are running at 40MHz then the fastest bus cycle is two clocks (50nsec). The fastest bus would be 16-bit demultiplexed. You didn't say what the size of the RAM is but I would suggest remapping /CS3 into segment zero and then using the PEC for the move. This is the fastest way to move data (the MOV instruction is injected in the pipeline upon the ADC interrupt, this also assumes the RAM is 16-bit wide).

    Let me know if you need an example or if this doesn't make sense to you.


    -Chris

Children
  • Chris,

    Thank you for your advice and yes, I would like an example. The size of the external RAM is 512KB. I'll go ahead and use PEC for the data transfer but how do I emapping /CS3 into segment zero? An example covering everything you said would be nice. Thanks!

  • Is there a reason why you need to have the ADC results in external RAM? Can you put them in the internal XRAM? The C16x family only allows the PEC to work in the first 64K of memory. You also know that the fastest the ADC can convert data (running at 40MHz) is around 9.7us.

    Mapping RAM (/CS3) into the first segment generally needs to have two chip selects connected and running open drain as not to lose all of the flash memory (since you have 512 Kbyte of RAM). So you basically can access the first part of the RAM memory on two different base addresses.

    You need to be careful on mapping chip selects. However, /CS0 has no address window so any other chip select can me mapped over it. You just need to give the start address (but as I said already this would mean you lose the same area for the flash). You need the flash to start at zero because of the interrupt vector table.

  • Chris,

    One of my project requirement is to collect around 500KB worth of data from an ADC channel; therefore, only the external RAM has the capacity to do so. After thinking about what you said, maybe PEC isn't such a good idea since PEC buffer is of type sdata where external RAM is of type xhuge.

    Right now, my problem is trying to minimize the time it takes to move data from ADDAT into the external RAM. 10us to move data from ADDAT to external RAM is way too long. Is there any method to reduce it to 1us or less with a 40MHz processor speed?

    Just FYI, Aater collecting 500KB of data, it will send it to a PC program through Ethernet.

    With that being said, will mapping /CS3 to the first segment still be beneficial? If yes, could you please provide me some example? Thanks.

  • Transferring a word to xhuge memory shouldn't take much longer than 1 us. Try something like this:

    unsigned int xhuge adc_results[100000];
    unsigned int xhuge *adc_ptr = adc_results;
    
    /* ADC conversion done ISR */
    void adc_isr(void) interrupt ADC_INT
    {
        /* reload ADC control registers if you must */
    
        /* save conversion result: */
        *adc_ptr++ = ADDAT;
    }
    

    That should do it. I don't think this will generate a lot of slow code.

    - mike

  • First, here are the bus settings that Phytec has called out for /CS3 "BUSCON3 = 0x04AF".

    So you have the solution provided by Mike which is perfectly fine. But this requires your code to service the ADC interrupt on every conversion (every 10usec). If this is not a problem then no need to continue.

    The alternative that I was thinking of would be to give up a block (actually two) of internal RAM (or XRAM) as an intermediate step to hold the ADC results and service it as a block transfer. The PEC would be used to move the ADC result after every conversion to the internal RAM (as an injected MOV until the temporary block of data is filled). The final PEC move would post the interrupt that is serviced by software. So for example, to have 262,144 results (512K of data) you could choose the transfer count to be 64. This means you would only vector to the ADC interrupt once out of 64 conversions or every 640usecs. Then the data movement to external RAM from internal RAM would be outside of the interrupt and consist of 4096 transactions (64 word transfer each transaction).

    #define BUF_SIZE (64)
    #define LIMIT (4096)
    
    extern unsigned int xhuge adc_results[];
    extern unsigned int xhuge *adc_ptr;
    
    bit bufferSelect;
    bit taskADCMove;
    unsigned int sdata adc_temp1[BUF_SIZE];
    unsigned int sdata adc_temp2[BUF_SIZE];
    unsigned int sdata *adc_temp_ptr;
    unsigned int sdata *adc_unload_ptr;
    unsigned int sdata transactions;
    
    /* Initialize ADC */
    void InitADC(void)
    {
      ADCON    =  0xC290;
      ADCIC    =  0x007A;       /* Use PEC channel 2 for ADC Conv INT:  */
      PECC2    =  0x0200 | BUF_SIZE;     /* load PEC2 control register */
      SRCP2    =  (unsigned int) (&ADDAT);         /* set source pointer */
      DSTP2    =  (unsigned int) (adc_temp1);  /* set destination pointer */
      bufferSelect = 0;
      transactions = 0;
      ADCON    |= 0x0080;                 /* set start bit */
    }
    
    
    /* ADC conversion complete ISR */
    void ADC_conversion_complete_ISR (void) interrupt 0x28 {
    
      PECC2  =  0x0200 | BUF_SIZE;          /* load PEC2 control register */
      SRCP2  =  (unsigned int) (&ADDAT);   /* set source pointer */
    
      bufferSelect ^= 1;                   /* move to alternate buffer */
    
      if (bufferSelect == 1) {
        DSTP2 = (unsigned int) (adc_temp2);  /* set destination pointer */
        adc_unload_ptr = adc_temp1;
      }
      else {
        DSTP2 = (unsigned int) (adc_temp1);  /* set destination pointer */
        adc_unload_ptr = adc_temp2;
      }
    
      taskADCMove = 1;         /* inform kernel of ADC move task is ready */
    }
    
    /* routine to move data to external RAM */
    void ADCMoveTask(void)
    {
      short i;
    
      for (i = 0; i < BUF_SIZE; i++) {
         *adc_ptr++ = *adc_unload_ptr;
      }
    
      if (++transactions > LIMIT-1) {
        ADCON &= 0xFF7F;
        /* issue task to move data across Ethernet */
      }
    }
    
    
    void TaskLoop(void) {
    
       for(;;) {   /* run state machine forever */
    
        if (taskADCMove == 1) {
          taskADCMove = 0;
          ADCMoveTask();
        }
      }
    }
    

    -Chris