Changeset 212


Ignore:
Timestamp:
Nov 1, 2010 3:01:09 PM (6 years ago)
Author:
df9dq
Message:

I2S-DMA stark vereinfacht. Asynchroner USB-Mode jetzt einwandfrei. DRM? :-)

Location:
trunk/Software/LPC
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/Software/LPC/fifisdr/src/FreeRTOSConfig.h

    r207 r212  
    119119numeric value the higher the interrupt priority). */ 
    120120#define configUSB_INTERRUPT_PRIORITY            6 
     121#define configDMA_INTERRUPT_PRIORITY        7 
    121122 
    122123 
  • trunk/Software/LPC/fifisdr/src/gpdma/dma.c

    r202 r212  
    3232 
    3333  /* Module variables */ 
    34 static xSemaphoreHandle xDmacChannelSemaphore[ DMAC_NUM_CHANNELS ]; 
    35                                             // Indicates that the channel is in use 
    36                                             // the corresponding DMAC channel is in use. 
    3734static xSemaphoreHandle g_xDmacSemaphore;   // Semaphore for exclusive access to DMAC resources. 
    38 static xSemaphoreHandle response_sema[ DMAC_NUM_CHANNELS ]; 
    39                                             // Queues to receive events from the channel 
    40  
     35 
     36 
     37static dma_CallbackFromISR callbacks[DMAC_NUM_CHANNELS]; 
    4138 
    4239 
     
    5249 
    5350  regVal = GPDMA->DMACIntTCStat; 
    54   if ( regVal ) 
    55   { 
    56     // (DMACIntTCClear is a write-only register!) 
    57 //TODO    GPDMA->DMACIntTCClear = regVal & DMACIntTCClear_MASK; 
    58   } 
     51  GPDMA->DMACIntTCClear = regVal; 
    5952 
    6053  // Report terminal count? 
     
    6356    if( regVal & (1u << n) ) 
    6457    { 
    65       // TODO: What if queue full?? 
    66       xSemaphoreGiveFromISR( xDmacChannelSemaphore[ n ], NULL ); 
    67  
    68       // Do we have a semaphore to give? 
    69       if( response_sema[ n ] ) 
    70       { 
    71         // Inform the caller 
    72         xSemaphoreGiveFromISR( response_sema[ n ], NULL ); 
    73  
    74         // Channel is free 
    75         // TODO: What if queue full?? 
    76         xSemaphoreGiveFromISR( xDmacChannelSemaphore[ n ], NULL ); 
     58      /* Callback handler */ 
     59      if (callbacks[n]) { 
     60          callbacks[n](DMA_STATUS_TERMINAL_COUNT, NULL); 
    7761      } 
    7862    } 
     
    9680void dmaInit( void ) 
    9781{ 
    98   int i; 
    99  
    10082  // Create semaphore for exclusive DMAC access 
    10183  vSemaphoreCreateBinary( g_xDmacSemaphore ); 
    10284  xSemaphoreGive( g_xDmacSemaphore ); 
    103  
    104   // Create semaphores for channel access 
    105   for( i = 0 ; i < DMAC_NUM_CHANNELS ; i++ ) 
    106   { 
    107     vSemaphoreCreateBinary( xDmacChannelSemaphore[ i ] ); 
    108     xSemaphoreGive( xDmacChannelSemaphore[ i ] ); 
    109   } 
    11085 
    11186  // Install interrupt handler 
     
    190165 
    191166 
     167/* Hack...  Set callback */ 
     168void dmaSetCallback (DMAC_HANDLE handle, dma_CallbackFromISR callback) 
     169{ 
     170    uint8_t channel = (uint8_t)handle; 
     171 
     172    callbacks[channel] = callback; 
     173} 
     174 
    192175 
    193176  /* 
     
    196179   * to the first list element. 
    197180   */ 
    198 DMAC_HANDLE dmaStartChannel( uint32_t config, const struct strLLI *lli, xSemaphoreHandle semaphore ) 
     181DMAC_HANDLE dmaStartChannel( uint32_t config, const struct strLLI *lli, dma_CallbackFromISR callback) 
    199182{ 
    200183  int channel; 
     
    215198      for( channel = 0 ; channel < DMAC_NUM_CHANNELS ; channel++ ) 
    216199      { 
    217         if( xSemaphoreTake( xDmacChannelSemaphore[ channel ], ( portTickType ) 5 ) == pdTRUE ) 
    218           break; 
     200        if (!(GPDMAChannel[channel].DMACCConfig & 1)) { 
     201            break; 
     202        } 
    219203      } 
    220204      if( channel < DMAC_NUM_CHANNELS ) 
    221205      { 
    222         // Remember the queue handle 
    223         response_sema[ channel ] = semaphore; 
     206        // Remember the callback 
     207        callbacks[ channel ] = callback; 
    224208 
    225209        // Clear any pending interrupt flags of the channel 
     
    261245  else 
    262246  { 
    263     // Release the semaphore for that channel 
    264     if( xSemaphoreGive( xDmacChannelSemaphore[ handle ] ) != pdTRUE ) 
    265       result = DMAC_INVALID_HANDLE; 
    266  
    267247    // Disable the channel (ignore data in FIFO) 
    268248    GPDMAChannel[handle].DMACCConfig = 0; 
  • trunk/Software/LPC/fifisdr/src/gpdma/dma.h

    r83 r212  
    4848#define DMAC_INSTALL_INT_HANDLER()                                    \ 
    4949    {                                                                 \ 
     50      NVIC_SetPriority(DMA_IRQn, configDMA_INTERRUPT_PRIORITY);       \ 
    5051      NVIC_EnableIRQ( DMA_IRQn );                                     \ 
    5152    } 
     
    179180                ) 
    180181 
     182/** Status code for the callback function. */ 
     183enum { 
     184    DMA_STATUS_TERMINAL_COUNT, 
     185    DMA_STATUS_ERROR, 
     186}; 
     187 
     188/** DMA callback function. */ 
     189typedef void (*dma_CallbackFromISR)(uint8_t status, void *parameter); 
     190 
    181191 
    182192  /*! \brief Initialize GPDMA block. 
     
    226236   *         <0 : An error number (DMAC_STATUS_CODE) 
    227237   */ 
    228 DMAC_HANDLE dmaStartChannel( uint32_t config, const struct strLLI *lli, xSemaphoreHandle semaphore ); 
     238DMAC_HANDLE dmaStartChannel( uint32_t config, const struct strLLI *lli, dma_CallbackFromISR callback); 
    229239 
    230240  /*! \brief Explicitely return a DMAC channel handle. 
     
    239249DMAC_STATUS_CODE dmaReleaseHandle( DMAC_HANDLE handle ); 
    240250 
     251/* Hack... */ 
     252void dmaSetCallback (DMAC_HANDLE handle, dma_CallbackFromISR callback); 
     253 
    241254#endif  // #ifndef __DMA_H 
    242255 
  • trunk/Software/LPC/fifisdr/src/init.c

    r206 r212  
    3939  SC->PCLKSEL0 = 0x00000003;  /* WDT=1/8                                    */ 
    4040  SC->PCLKSEL1 = 0x00800000;  /* I2S=1/2                                    */ 
    41   SC->PCONP    = 0xA8E99406;  /* TIMER0(1), TIMER1(2), SSP1(10), ADC(12),   */ 
     41  SC->PCONP    = 0xA8E98406;  /* TIMER0(1), TIMER1(2), SSP1(10),            */ 
    4242                              /* GPIO(15), RIT(16), I2C1(19), SSP0(21)      */ 
    4343                              /* TIMER2(22), TIMER3(23), I2S(27), DMA(29)   */ 
  • trunk/Software/LPC/fifisdr/src/lpc1768-rom.ld

    r83 r212  
    108108  } >ram2 AT>flash 
    109109 
    110   .ram2bss : 
     110  .ram2bss (NOLOAD) : 
    111111  { 
    112112    __bss2_start__ = .; 
     113    *(.ram2bss) 
    113114    __bss2_end__ = ALIGN(4); 
    114115  } >ram2 
     
    120121  } >ram3 AT>flash 
    121122 
    122   .ram3bss : 
     123  .ram3bss (NOLOAD) : 
    123124  { 
    124125    __bss3_start__ = .; 
  • trunk/Software/LPC/fifisdr/src/lpcusb/usbclass.c

    r209 r212  
    7272static int16_t currentVolume; 
    7373static uint32_t current_sample_rate; 
    74  
    75 /* 
    76  * For audio DMA 
    77  */ 
    78  
    79 /* Number of available words in audio buffer */ 
    80 static uint32_t audio_count; 
     74static uint8_t i2s_active = 0; 
     75static struct { 
     76    uint32_t timerModulus; 
     77    uint32_t lastDmaTimestamp; 
     78    uint32_t readIndex; 
     79} fifiaudio; 
     80 
    8181 
    8282/* 
     
    9999 
    100100 
    101 /* Make sure that you specify enough samples to take at least >1 ms of 
    102  * samples per buffer (LLI) at the highest sample rate. 
    103  * 96 kS/s: 128 samples = 1.33 ms 
    104  */ 
    105 #define I2S_DMA_SAMPLES_PER_LLI (128) 
    106 static uint32_t audio_buffer[2][I2S_DMA_SAMPLES_PER_LLI * 2] 
    107     __attribute__((section(".ram2bss"))); 
    108  
    109 // TODO : Move from double buffering to ringbuffer 
    110 static const struct strLLI audio_lli[2] = 
    111 { 
    112 #if AUDIO_SAMPLES == 16 
    113     { 
    114         .source = (uint32_t)&I2S->I2SRXFIFO, 
    115         .destination = (uint32_t)&audio_buffer[0], 
    116         .next = (uint32_t)&audio_lli[1], 
    117         .control = DMAC_CONTROL_WORD( 
    118             (I2S_DMA_SAMPLES_PER_LLI * 1), 
    119             DMAC_BURSTSIZE_1, 
    120             DMAC_BURSTSIZE_1, 
    121             DMAC_TRANSFERWIDTH_32, 
    122             DMAC_TRANSFERWIDTH_32, 
    123             DMAC_NO_INCREMENT, 
    124             DMAC_INCREMENT, 
    125             DMAC_TC_OFF) 
    126     }, 
    127     { 
    128         .source = (uint32_t)&I2S->I2SRXFIFO, 
    129         .destination = (uint32_t)&audio_buffer[1], 
    130         .next = (uint32_t)&audio_lli[0], 
    131         .control = DMAC_CONTROL_WORD( 
    132             (I2S_DMA_SAMPLES_PER_LLI * 1), 
    133             DMAC_BURSTSIZE_1, 
    134             DMAC_BURSTSIZE_1, 
    135             DMAC_TRANSFERWIDTH_32, 
    136             DMAC_TRANSFERWIDTH_32, 
    137             DMAC_NO_INCREMENT, 
    138             DMAC_INCREMENT, 
    139             DMAC_TC_OFF) 
    140     }, 
    141 #endif 
    142 #if AUDIO_SAMPLES == 32 
    143     { 
    144         .source = (uint32_t)&I2S->I2SRXFIFO, 
    145         .destination = (uint32_t)&audio_buffer[0], 
    146         .next = (uint32_t)&audio_lli[1], 
    147         .control = DMAC_CONTROL_WORD( 
    148             (I2S_DMA_SAMPLES_PER_LLI * 2), 
    149             DMAC_BURSTSIZE_4, 
    150             DMAC_BURSTSIZE_4, 
    151             DMAC_TRANSFERWIDTH_32, 
    152             DMAC_TRANSFERWIDTH_32, 
    153             DMAC_NO_INCREMENT, 
    154             DMAC_INCREMENT, 
    155             DMAC_TC_OFF) 
    156     }, 
    157     { 
    158         .source = (uint32_t)&I2S->I2SRXFIFO, 
    159         .destination = (uint32_t)&audio_buffer[1], 
    160         .next = (uint32_t)&audio_lli[0], 
    161         .control = DMAC_CONTROL_WORD( 
    162             (I2S_DMA_SAMPLES_PER_LLI * 2), 
    163             DMAC_BURSTSIZE_4, 
    164             DMAC_BURSTSIZE_4, 
    165             DMAC_TRANSFERWIDTH_32, 
    166             DMAC_TRANSFERWIDTH_32, 
    167             DMAC_NO_INCREMENT, 
    168             DMAC_INCREMENT, 
    169             DMAC_TC_OFF) 
    170     }, 
    171 #endif 
     101#define I2S_NUM_SAMPLES (1024) 
     102 
     103/** Ring buffer for audio frames. */ 
     104static uint32_t audioBuffer[I2S_NUM_SAMPLES + 97] __attribute__((section(".ram2bss"))); 
     105 
     106 
     107const struct strLLI audioLli = { 
     108    .source         = (uint32_t)&I2S->I2SRXFIFO, 
     109    .destination    = (uint32_t)&audioBuffer[0], 
     110    .next           = (uint32_t)&audioLli, 
     111    .control        = DMAC_CONTROL_WORD( 
     112                            I2S_NUM_SAMPLES, 
     113                            DMAC_BURSTSIZE_4, 
     114                            DMAC_BURSTSIZE_4, 
     115                            DMAC_TRANSFERWIDTH_32, 
     116                            DMAC_TRANSFERWIDTH_32, 
     117                            DMAC_NO_INCREMENT, 
     118                            DMAC_INCREMENT, 
     119                            DMAC_TC_ON), 
    172120}; 
    173121 
    174122 
     123/** Callback for I2S DMA. */ 
     124static void fifiaudio_dmaCallbackFromISR (uint8_t status __attribute__((unused)), 
     125                                          void *parameter __attribute__((unused))) 
     126{ 
     127    /* Take a time stamp */ 
     128    fifiaudio.lastDmaTimestamp = TIM3->TC; 
     129} 
     130 
    175131 
    176132static void i2sStop( void ) 
    177133{ 
    178134        // cleanly stop I2S DMA 
    179     GPDMAChannel[0].DMACCConfig |= (1 << 18); 
    180     while( GPDMAChannel[0].DMACCConfig & (1 << 17) ); 
     135//    GPDMAChannel[0].DMACCConfig |= (1 << 18); 
     136//    while( GPDMAChannel[0].DMACCConfig & (1 << 17) ); 
    181137    // disable I2S DMA 
    182138    GPDMAChannel[0].DMACCConfig &= ~1; 
     
    189145static void i2sStart( uint32_t sample_rate ) 
    190146{ 
    191  
    192         //TODO 
    193         if(!(GPDMAChannel[0].DMACCConfig & 1)) 
    194         { 
    195                 /* Start DMA for I2S */ 
    196         GPDMA->DMACIntTCClear = 1 << 0; 
    197         GPDMA->DMACIntErrClr = 1 << 0; 
    198         GPDMAChannel[0].DMACCDestAddr = audio_lli[0].destination; 
    199         GPDMAChannel[0].DMACCLLI = audio_lli[0].next; 
    200         GPDMAChannel[0].DMACCControl = audio_lli[0].control; 
    201         GPDMAChannel[0].DMACCConfig = 
     147    fifiaudio.timerModulus = ((configCPU_CLOCK_HZ / 1000ul) * I2S_NUM_SAMPLES) / (4 * (current_sample_rate/1000ul)); 
     148    TIM3->MR0 = fifiaudio.timerModulus - 1; 
     149    TIM3->TC = 0; /* Reset counter */ 
     150 
     151    /* Start DMA */ 
     152    GPDMA->DMACIntTCClear = 1 << 0; 
     153    GPDMA->DMACIntErrClr = 1 << 0; 
     154    GPDMAChannel[0].DMACCSrcAddr = audioLli.source; 
     155    GPDMAChannel[0].DMACCDestAddr = audioLli.destination; 
     156    GPDMAChannel[0].DMACCLLI = audioLli.next; 
     157    GPDMAChannel[0].DMACCControl = audioLli.control; 
     158    GPDMAChannel[0].DMACCConfig = 
    202159            DMAC_CONFIG_WORD( 
    203160              DMAC_ID_I2S_0, 
     
    207164              DMAC_TERMINAL_COUNT_INT_ON 
    208165            ); 
    209         } 
     166    dmaSetCallback (0, fifiaudio_dmaCallbackFromISR); 
    210167 
    211168        #if AUDIO_SAMPLES == 16 
     
    250207                } 
    251208 
    252         #if AUDIO_SAMPLES == 16 
    253                 /* Enable DMA1 for RX, DMA request threshold = 1 */ 
    254                 I2S->I2SDMA1 =  (1 << 0) |              // enable DMA for I2S RX 
    255                                                 (1 << 8);               // trigger level for DMA rx req = 1 
    256         #endif 
    257         #if AUDIO_SAMPLES == 32 
    258                 /* Enable DMA1 for RX, DMA request threshold = 4 */ 
    259                 I2S->I2SDMA1 = (1 << 0) | (4 << 8); 
    260         #endif 
     209    /* Enable DMA1 for RX, DMA request threshold = 1 */ 
     210    I2S->I2SDMA1 =      (1 << 0) |              // enable DMA for I2S RX 
     211                    (4 << 8);           // trigger level for DMA rx req = 4 
    261212 
    262213        I2S->I2SDAO &= ~(1 << 4);       // de-assert reset 
     
    276227                                                                (1 << 4) |              // Isochronous endpoint 
    277228                                                                (0x01 << 16);   // DMA Buffer length in packets 
    278         usb_dma_desc[0].dma_buffer_start = audio_buffer[0]; 
     229        usb_dma_desc[0].dma_buffer_start = audioBuffer; 
    279230        usb_dma_desc[0].value3 = 0;                                     // reset status etc to 0 
    280231        /* 
     
    292243        usb_dma_desc[0].isoc_packetsize_memory_address = &usb_isoc_packets[0]; 
    293244 
    294         usb_isoc_packets[1] =   (1 << 16) |             // Frame #1 
    295                                                         33;                             // Length = 33 
    296  
    297         usb_dma_desc[1].next = &usb_dma_desc[0]; 
    298         usb_dma_desc[1].value1 =        (1 << 2) |              // next DD valid = 1 (TODO ???) 
    299                                                                 (1 << 4) |              // Isochronous endpoint 
    300                                                                 (0x0001 << 16); // DMA Buffer length in packets 
    301         usb_dma_desc[1].dma_buffer_start = audio_buffer[1]; 
    302         usb_dma_desc[1].value3 = 0; 
    303         usb_dma_desc[1].isoc_packetsize_memory_address = &usb_isoc_packets[1]; 
    304  
    305         usb_udca[2*3+1] = &usb_dma_desc[0]; 
     245    usb_isoc_packets[1] =   (1 << 16) |         // Frame #1 
     246                            33;                 // Length = 33 
     247 
     248    usb_dma_desc[1].next = &usb_dma_desc[0]; 
     249    usb_dma_desc[1].value1 = (1 << 2) |         // next DD valid = 1 (TODO ???) 
     250                             (1 << 4) |         // Isochronous endpoint 
     251                             (0x0001 << 16);    // DMA Buffer length in packets 
     252    usb_dma_desc[1].dma_buffer_start = audioBuffer; 
     253    usb_dma_desc[1].value3 = 0; 
     254    usb_dma_desc[1].isoc_packetsize_memory_address = &usb_isoc_packets[1]; 
     255 
     256    usb_udca[2*3+1] = &usb_dma_desc[0]; 
    306257} 
    307258 
     
    311262static void setUdaVolume (int16_t volume) 
    312263{ 
    313     if (volume == 0) { 
     264    if (volume < 0) { 
     265        GPIO4->FIOCLR = 0x10000000; 
     266        GPIO4->FIODIR |= 0x10000000;        /* P4.28=UDA1361_PWON (low = power-down) */ 
     267    } 
     268    else if (volume == 0) { 
    314269        GPIO4->FIODIR &= ~0x10000000;       /* P4.28=UDA1361_PWON (floating = 0 dB) */ 
    315270    } 
     
    448403 
    449404 
    450 static void USBFrameHandler (unsigned short wFrame) 
    451 { 
    452     ( void ) wFrame; 
    453     int i, j; 
    454  
    455     /* Is I2S DMA running? */ 
    456     if( GPDMAChannel[0].DMACCConfig & 1 ) 
    457     { 
    458         /* Stop current DMA transfer, and remember the amount of data transferred 
    459          * so far. Then let the DMA continue with the next LLI. 
    460          * Copy as much audio data as possible for use with the USB DMA. 
    461          */ 
    462  
    463         /* Set the halt bit, and wait for the channel to become inactive */ 
    464         GPDMAChannel[0].DMACCConfig |= (1 << 18); 
    465         while( GPDMAChannel[0].DMACCConfig & (1 << 17) ); 
    466  
    467         /* Get the number of transfers */ 
    468     #if AUDIO_SAMPLES == 16 
    469         audio_count = ((I2S_DMA_SAMPLES_PER_LLI * 1) - (GPDMAChannel[0].DMACCControl & 0xFFF)); 
    470     #endif 
    471     #if AUDIO_SAMPLES == 32 
    472         audio_count = ((I2S_DMA_SAMPLES_PER_LLI * 2) - (GPDMAChannel[0].DMACCControl & 0xFFF)); 
    473     #endif 
    474  
    475         /* Disable the DMA */ 
    476         GPDMAChannel[0].DMACCConfig &= ~1; 
    477  
    478         /* Start DMA with next LLI */ 
    479         i = (GPDMAChannel[0].DMACCLLI == (uint32_t)&audio_lli[1]) ? 1 : 0; 
    480         j = (i == 0) ? 1 : 0; 
    481  
    482         GPDMA->DMACIntTCClear = 1 << 0; 
    483         GPDMA->DMACIntErrClr = 1 << 0; 
    484         GPDMAChannel[0].DMACCDestAddr = audio_lli[i].destination; 
    485         GPDMAChannel[0].DMACCLLI = audio_lli[i].next; 
    486         GPDMAChannel[0].DMACCControl = audio_lli[i].control; 
    487         GPDMAChannel[0].DMACCConfig = 
    488             DMAC_CONFIG_WORD( 
    489               DMAC_ID_I2S_0, 
    490               DMAC_ID_DUMMY, 
    491               DMAC_FLOW_P2M_DMAC, 
    492               DMAC_ERROR_INT_OFF, 
    493               DMAC_TERMINAL_COUNT_INT_ON 
    494             ); 
    495  
    496 // TODO Nasty hack for the moment. EP should be reconfigured in response to a SET_INTERFACE request. 
    497 //USBHwEPConfig(AUDIO_IN_EP, USB_ISOC_SIZE); 
    498  
    499         /* Update DMA descriptors */ 
    500         i = (i == 0) ? 1 : 0; 
    501  
    502         usb_isoc_packets[i] = (1 << 16) | (4 * audio_count); 
    503  
    504         usb_dma_desc[i].value1 = (1 << 2) | (1 << 4) | (0x0001 << 16); 
    505         usb_dma_desc[i].dma_buffer_start = audio_buffer[i]; 
    506         usb_dma_desc[i].value3 = 0; 
    507         usb_dma_desc[i].isoc_packetsize_memory_address = &usb_isoc_packets[i]; 
    508  
    509         /* Underrun? */ 
    510         if( USB->USBNDDRIntSt & (1 << 7) ) 
    511         { 
    512             /* Clear it */ 
    513             USB->USBNDDRIntClr = (1 << 7); 
    514             i = (i == 0) ? 1 : 0; 
    515             usb_isoc_packets[i] = (1 << 16) | (4 * audio_count); 
    516             usb_dma_desc[i].value1 = (1 << 2) | (1 << 4) | (0x0001 << 16); 
    517             usb_dma_desc[i].dma_buffer_start = audio_buffer[i]; 
    518             usb_dma_desc[i].value3 = 0; 
    519             usb_dma_desc[i].isoc_packetsize_memory_address = &usb_isoc_packets[i]; 
    520             usb_udca[2*3+1] = &usb_dma_desc[i]; 
     405static void USBFrameHandler (unsigned short wFrame __attribute__((unused))) 
     406{ 
     407    int32_t temp; 
     408    int32_t currentPos; 
     409    int32_t delta; 
     410    int32_t i; 
     411 
     412 
     413    /* Do nothing if channel isn't active */ 
     414    if (!i2s_active) { 
     415        return; 
     416    } 
     417 
     418    /* Take timer snapshot */ 
     419    temp = (int32_t)TIM3->TC; 
     420 
     421    /* Are we in sync? 
     422     * Sync is achieved if the read index is half-way from the current write position, 
     423     * plus/minus some samples. 
     424     */ 
     425 
     426    /* The next calculation works for both cases: current > start and current < start. 
     427     * The addition of the modulus guarantees a positive result. 
     428     * Note: It is possible that the DMA interrupt fires at this very moment, and updates the 
     429     *       lastDmaTimestamp. This is no problem, since the timer modulus is chosen to be 
     430     *       exactly one DMA period, and therefore it is expected that the lastDmaTimestamp 
     431     *       will not change (significantly). 
     432     */ 
     433    currentPos = fifiaudio.timerModulus + temp - fifiaudio.lastDmaTimestamp; 
     434    currentPos %= fifiaudio.timerModulus; 
     435 
     436    /* Convert to #samples: pos /= (CCLK/4) / samplerate 
     437     * Move to diameter: pos = (pos + NUM_SAMPLES/2) % NUM_SAMPLES 
     438     * The calculation below does it all in one without rounding and overflow problems. 
     439     */ 
     440    currentPos = (2 * currentPos * (current_sample_rate/1000ul) + 
     441                  I2S_NUM_SAMPLES * (configCPU_CLOCK_HZ / 4000ul))  / 
     442                  (configCPU_CLOCK_HZ / 2000ul); 
     443    currentPos %= I2S_NUM_SAMPLES; 
     444 
     445    /* Calculate difference in the range -512...+511. Nominal value is 0. */ 
     446    temp = (((3*I2S_NUM_SAMPLES)/2 + fifiaudio.readIndex - currentPos) % I2S_NUM_SAMPLES); 
     447    temp -= I2S_NUM_SAMPLES / 2; 
     448 
     449    /* Calculate necessary adjustment. */ 
     450    delta = 0; 
     451    if ((temp < -50) || (temp > +50)) { 
     452        /* Too far off. Force sync, and accept losing samples. */ 
     453        fifiaudio.readIndex = currentPos; 
     454    } 
     455    else if (temp < -5) { 
     456        /* Internal clock too fast. Long packet (+1 sample) */ 
     457        delta = +1; 
     458    } 
     459    else if (temp > +5) { 
     460        /* Internal clock too slow. Short packet (-1 sample) */ 
     461        delta = -1; 
     462    } 
     463 
     464    /* Copy from start of buffer to beyond the buffer end if necessary. */ 
     465    temp = fifiaudio.readIndex + (current_sample_rate/1000ul) + delta; 
     466    if (temp > I2S_NUM_SAMPLES) { 
     467        while (temp - I2S_NUM_SAMPLES) { 
     468            temp--; 
     469            audioBuffer[temp] = audioBuffer[temp - I2S_NUM_SAMPLES]; 
    521470        } 
    522471    } 
     472 
     473    i = (usb_dma_desc[0].value3 & 1) ? 0 : 1; 
     474 
     475    usb_isoc_packets[i] = (1 << 16) | (4 * (current_sample_rate/1000ul + delta)); 
     476 
     477    usb_dma_desc[i].value1 = (1 << 2) | (1 << 4) | (0x0001 << 16); 
     478    usb_dma_desc[i].dma_buffer_start = &audioBuffer[fifiaudio.readIndex]; 
     479    usb_dma_desc[i].isoc_packetsize_memory_address = &usb_isoc_packets[i]; 
     480    usb_dma_desc[i].value3 = 0; 
     481 
     482    /* Underrun? */ 
     483    if (USB->USBNDDRIntSt & (1 << 7)) { 
     484        /* Clear it */ 
     485        USB->USBNDDRIntClr = (1 << 7); 
     486    } 
     487 
     488    /* Advance read pointer */ 
     489    fifiaudio.readIndex += ((current_sample_rate/1000ul) + delta); 
     490    fifiaudio.readIndex %= I2S_NUM_SAMPLES; 
    523491} 
    524492 
     
    528496{ 
    529497    USBQUEUE_TYPE message; 
    530     uint8_t     i2s_active = 0; 
    531  
     498 
     499 
     500    /* Timer3 is used as a high-resolution timing reference to help detect clock drift. */ 
     501    SC->PCONP |= (1ul << 23); 
     502    TIM3->TCR = 2;                      /* Stop and reset */ 
     503    TIM3->PR = 0;                       /* Maximum resolution */ 
     504    TIM3->MR0 = 1; 
     505    TIM3->MCR = 2;                      /* Reset by MR0 */ 
     506    TIM3->TCR = 1;                      /* Start */ 
     507 
     508    current_sample_rate = 48000ul; 
     509    fifiaudio.timerModulus = 532000ul; 
    532510 
    533511    /* Task communication */ 
     
    550528//    USBRegisterRequestHandler(REQTYPE_TYPE_VENDOR, HandleVendorRequest, abVendorReqData); 
    551529 
    552     // register frame handler 
    553     USBHwRegisterFrameHandler(USBFrameHandler); 
    554  
    555     // enable bulk-in interrupts on NAKs 
    556     USBHwNakIntEnable(INACK_BI); 
    557  
    558 softrock_init(); 
    559  
    560     usbd_start(); 
    561  
    562     // connect to bus 
    563     USBHwConnect(true); 
    564  
    565530    // I2S interface 
    566531    dmaInit(); 
    567532    //TODO: Fehlerbehandlung wenn DMA nicht gestartet werden kann (LED?!) 
    568     while( dmaResume() == DMAC_BUSY );  // DMA has to be started 
     533    while( dmaResume() == DMAC_BUSY );  // DMA has to be started 
     534 
     535    // register frame handler 
     536    USBHwRegisterFrameHandler(USBFrameHandler); 
     537 
     538    // enable bulk-in interrupts on NAKs 
     539    USBHwNakIntEnable(INACK_BI); 
     540 
     541softrock_init(); 
     542 
     543    usbd_start(); 
     544 
     545    // connect to bus 
     546    USBHwConnect(true); 
    569547 
    570548    for( ;; ) 
Note: See TracChangeset for help on using the changeset viewer.