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
  • 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

Reply
  • 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

Children
No data