host_audio_task.c

Go to the documentation of this file.
00001 /*This file has been prepared for Doxygen automatic documentation generation.*/
00013 
00014 /* Copyright (c) 2007, Atmel Corporation All rights reserved.
00015  *
00016  * Redistribution and use in source and binary forms, with or without
00017  * modification, are permitted provided that the following conditions are met:
00018  *
00019  * 1. Redistributions of source code must retain the above copyright notice,
00020  * this list of conditions and the following disclaimer.
00021  *
00022  * 2. Redistributions in binary form must reproduce the above copyright notice,
00023  * this list of conditions and the following disclaimer in the documentation
00024  * and/or other materials provided with the distribution.
00025  *
00026  * 3. The name of ATMEL may not be used to endorse or promote products derived
00027  * from this software without specific prior written permission.
00028  *
00029  * THIS SOFTWARE IS PROVIDED BY ATMEL ``AS IS'' AND ANY EXPRESS OR IMPLIED
00030  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00031  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND
00032  * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT,
00033  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00034  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00035  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00036  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00037  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00038  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00039  */
00040 
00041 //_____  I N C L U D E S ___________________________________________________
00042 
00043 #include "config.h"
00044 #include "conf_usb.h"
00045 #include "host_audio_task.h"
00046 #include "modules/usb/host_chap9/usb_host_task.h"
00047 #include "modules/usb/host_chap9/usb_host_enum.h"
00048 #include "lib_mcu/usb/usb_drv.h"
00049 
00050 //_____ M A C R O S ________________________________________________________
00051 
00052 #ifndef LOG_STR_CODE
00053 #define LOG_STR_CODE(str)
00054 #else
00055 U8 code log_audio_connect[]="Audio Connected";
00056 #endif
00057 
00058 //_____ D E F I N I T I O N S ______________________________________________
00059 
00060 #define   AUDIO_STREAM_SIZE       16
00061 
00062 
00063 //_____ D E C L A R A T I O N S ____________________________________________
00064 
00065 volatile U8  audio_connected;
00066 volatile U8  audio_cpt_sof;
00067 U8  mute;
00068 
00069 U8  pipe_audio_in;
00070 U8  interf_audio_stream;
00071 
00072 volatile U8  audio_stream_in[AUDIO_STREAM_SIZE];
00073 volatile U8  audio_stream_ptr_wr;
00074 volatile U8  audio_stream_ptr_rd;
00075 volatile U8  audio_stream_size;
00076 volatile bit audio_stream_empty;
00077 
00078 
00085 void host_audio_task_init(void)
00086 {
00087    Leds_init();
00088    audio_connected = 0;
00089    Joy_init();
00090    
00091    // D/A converter output rate management
00092    // At 8 kHz, output should be updated every 125µs. But real-time issues may occur between both USB devices :
00093    // The Host send a token to the Device every millisecond, to get back a new samples frame.
00094    // On the Device side, this frame is loaded into endpoint every millisecond. So some frames may be missed in
00095    // the case where the endpoint is not yet validated while the token has been sent.
00096    // To decrease error cases and probability, the device sample rate has been fixed to 120µs.
00097    // The Host ouput rate is also set to 120µs.
00098    TCCR2A=0x02;         // Prescaler div8
00099    OCR2A=120;           // Reload value to count 8x120=960 for FOSC 8MHz =>120µS refresh rate
00100    TCCR2B=0x02;         // Timer 2 mode CTC
00101    TIMSK2|=(1<<OCIE2A); // Enable compare interrupt
00102    
00103    // D/A converter hardware configuration
00104    // In this case, user is free to do what he wants
00105    Dac_output_init();
00106 }
00107 
00108 
00109 
00115 void host_audio_task(void)
00116 {
00117 U8 i, j;
00118 
00119    // Audio Device Management
00120    // *********************
00121    if(Is_host_ready())
00122    {
00123       if(Is_new_device_connection_event())   // Device connection
00124       {
00125          for(i=0;i<Get_nb_supported_interface();i++)
00126          {
00127             // Audio Streaming Interface
00128             // Select the audio streaming interface that has an IN PIPE
00129             if((Get_class(i)==AUDIO_AS_INTERFACE_CLASS) && (Get_subclass(i)==AUDIO_AS_INTERFACE_SUB_CLASS) && (Get_nb_ep(i) != 0))
00130             {
00131                for (j=0 ; j<Get_nb_ep(i) ; j++)
00132                {
00133                  if (Is_ep_addr_in(Get_ep_addr(i,j)))
00134                  {
00135                    // Log in device
00136                    audio_connected=1;
00137                    audio_stream_ptr_wr = 0;
00138                    audio_stream_ptr_rd = 0;
00139                    audio_stream_empty = TRUE;
00140                    Led0_on();
00141                    Host_enable_sof_interrupt();
00142                    LOG_STR_CODE(log_audio_connect);
00143                    
00144                    // Select and enable ISOCHRONOUS pipe
00145                    pipe_audio_in = host_get_hwd_pipe_nb(Get_ep_addr(i,j));
00146                    Host_select_pipe(PIPE_AUDIO_IN);
00147                    Host_continuous_in_mode();
00148                    Host_unfreeze_pipe();
00149                    
00150                    // Set the Device in Mute mode
00151                    mute = TRUE;
00152                    Led3_on();   // LED3 is ON when device muted
00153                    host_audio_set_cur(mute);        // set device default state : muted
00154                    
00155                    // Enable alternate streaming interface
00156                    interf_audio_stream = i;                     // store interface number
00157                    host_set_interface(interf_audio_stream,1);   // enable streaming interface with "alternate 1" on Device
00158                    break;
00159                  }
00160                }
00161             }
00162          }
00163       }
00164 
00165       if (audio_connected)
00166       {
00167          // Check in AUDIO_PIPE_IN for incoming stream
00168          // ******************************************
00169          Host_select_pipe(PIPE_AUDIO_IN);
00170          
00171          // Error management : clear any error (time-out, CRC, etc...) and unfreeze pipe if error flag rises
00172          // Error flag rises after three errors. Errors can be identified in UPERRX register.
00173          if (Is_host_pipe_error())
00174          {
00175            Host_ack_all_errors();
00176            Host_unfreeze_pipe();
00177          }
00178 
00179          // Stream management
00180          if (Is_host_in_received() && (Is_host_stall()==FALSE))
00181          {
00182            // Pipe has received a new frame !
00183            Disable_interrupt();   // to avoid interrupt access to audio_stream_in[] buffer
00184            while ((Host_data_length_U8() != 0) && (audio_stream_ptr_wr != AUDIO_STREAM_SIZE))
00185            {
00186               audio_stream_in[audio_stream_ptr_wr] = Host_read_byte();
00187               audio_stream_ptr_wr++;
00188            }
00189            audio_stream_size = audio_stream_ptr_wr;
00190            audio_stream_empty = FALSE;
00191            Host_ack_in_received();  // all the pipe data has been read
00192            Host_send_in();
00193            Enable_interrupt();
00194          }
00195          
00196          // Mute control : toggle MUTE state with Joystick DOWN direction
00197          if (Is_joy_down())
00198          {
00199            audio_cpt_sof = 0;
00200            while (audio_cpt_sof != 10); // debounce
00201            if (mute == TRUE)
00202            {
00203              mute=FALSE;
00204              Led3_off();
00205            }
00206            else
00207            {
00208              mute=TRUE;
00209              Led3_on();
00210            }
00211            host_audio_set_cur(mute);
00212            while (Is_joy_down());
00213            audio_cpt_sof = 0;           // debounce
00214            while (audio_cpt_sof != 10);
00215          }
00216       }
00217    }
00218 
00219    // Device disconnection...
00220    if(Is_device_disconnection_event())
00221    {
00222       Leds_off();
00223       audio_stream_empty = TRUE;
00224       audio_stream_ptr_rd = 0;
00225       audio_stream_ptr_wr = 0;
00226       audio_stream_size = 0;
00227       audio_connected = 0;
00228    }
00229 }
00230 
00231 
00232 
00244 void sof_action(void)
00245 {
00246    audio_cpt_sof++;
00247 }
00248 
00249 
00250 
00251 
00262 #ifdef __GNUC__
00263  ISR(TIMER2_COMPA_vect)
00264 #else
00265 #pragma vector = TIMER2_COMPA_vect
00266 __interrupt void timer2_comp_interrupt()
00267 #endif
00268 {
00269    U8   data_dac;
00270    U16  data_16b;
00271 
00272    if (audio_connected)
00273    {
00274       if (audio_stream_empty == FALSE)
00275       {
00276         // Get the sample word (16 bits)
00277         data_16b = audio_stream_in[audio_stream_ptr_rd];
00278         audio_stream_ptr_rd++;
00279         data_16b |= ((U16) (audio_stream_in[audio_stream_ptr_rd])) << 8;
00280         audio_stream_ptr_rd++;
00281         
00282         // Decode PCM 16 bits word to 8 bits unsigned
00283         data_16b ^= 0x8000; // complement MSB
00284         data_dac = (U8)(data_16b>>8);
00285         
00286         // Drives R-2R ladder (uses a complete PORT ; PORTA is free on STK525)
00287         DAC_SendPort(data_dac);
00288         
00289         // Check if end of buffer reached
00290         if (audio_stream_ptr_rd == audio_stream_size) // no more data to read
00291         {
00292           audio_stream_ptr_rd = 0;
00293           audio_stream_ptr_wr = 0;
00294           audio_stream_size = 0;
00295           audio_stream_empty = TRUE;
00296         }
00297       }
00298    }
00299 }
00300 
00301 
00302 
00311 void DAC_SendPort(U8 data_dac)
00312 {
00313   U8   port_value;
00314   
00315   // DAC_OUT value must be set to the value specified by your external DAC ladder configuration
00316 #if   (DAC_OUT==PORT_A_RIGHT)
00317   // In this configuration, see the R-2R ladder configuration on the "R2R_LADDER_RIGHT" schematic
00318   PORTA = data_dac;
00319 #elif (DAC_OUT==PORT_A_CPLX)
00320   // In this configuration (easier to mount directly on EXPAND0 connector...), the connexions of the PORTA signals are not
00321   // the same that for the R2R_LADDER_RIGHT schematic. The resistor structure is the same, but the port connexions are differents :
00322   // see R2R_LADDER_CPLX schematic.
00323   port_value  = (data_dac&0x01);          // bit 0 : portA,0
00324   port_value |= (data_dac&0x02)<<(2-1);   // bit 1 : portA,2
00325   port_value |= (data_dac&0x04)<<(4-2);   // bit 2 : portA,4
00326   port_value |= (data_dac&0x08)<<(6-3);   // bit 3 : portA,6
00327   port_value |= (data_dac&0x10)<<(7-4);   // bit 4 : portA,7
00328   port_value |= (data_dac&0x20);          // bit 5 : portA,5
00329   port_value |= (data_dac&0x40)>>(6-3);   // bit 6 : portA,3
00330   port_value |= (data_dac&0x80)>>(7-1);   // bit 7 : portA,1
00331   PORTA = port_value;
00332 #endif
00333 }
00334 
00335 

Generated on Fri Oct 31 15:19:18 2008 for ATMEL by  doxygen 1.5.3