NOTICE: The Processors Wiki will End-of-Life on January 15, 2021. It is recommended to download any files or other content you may need that are hosted on processors.wiki.ti.com. The site is now set to read only.

Template:RemoTI-1.4.0-AdvancedRemote-Voice

From Texas Instruments Wiki
Jump to: navigation, search

Detailed guide to add Voice support for the Advanced Remote project[edit]

This section describes all steps required to add the Voice remote functionality to RemoTI-1.4.0. There are several aspects and gotchas to consider. Each code snippet that is added comes with a brief comment of why it is added.

Project options update[edit]

  1. Add $PROJ_DIR$\..\..\..\..\COMPONENTS\audio\include to the include paths
  2. Add to the pre-compiler options the following two defines
  3.   
      CC2533F96_VRC_REVB
      RAS_LIB
      
    
    IncludePath-Define-ForVoiceRemote.png
  4. We need to link with the audio library, in addition to the network library. Instead of adding the path to the compile options, we add a folder in the project, and then place both libraries there.
  5. AudioLibraryFolderInIARproject.png
    
  6. Uncheck the box which includes command line arguments for the linker. This is required since we add the library to the project in a new folder.
  7. UncheckIncludeCommandLineArgumentsForLinker.png
    
  8. We also need to add hal_codec.c to drive the codec
  9. AddAudioCodecDriverInIARproject.png
    
  10. To improve throughput and processing time we need to use compiler optimization settings for speed
  11. AudioIARprojectOptimizationForSpeed.png
    

Source files update[edit]

Application[edit]

In the main application code, rsa_point.c

  1. Include headers
  2. 
    #include "hal_codec.h"
    #include "ras_lib.h"
    
    
  3. Add stream event to the event list
  4. 
    // RSA Events
    #define RSA_EVT_INIT                    0x0001
    ...
    #ifdef RAS_LIB
    #define RSA_EVT_STOP_STREAM             0x0100
    #endif 
    
    
  5. Add stream state to the state enum
  6. 
    // RSA States
    enum
    {
    ...
     RSA_STATE_POLLING,
    #ifdef RAS_LIB
     RSA_STATE_STREAM,
    #endif
    };
    
    
  7. Add action define for audio and "push-to-talk". These defines serve as function pointer table index in the array rsaAppKeyActions. We simply subtract 0xB0 to use them as index.
  8. 
    #define RSA_ACT_TOGGLE_POLL        0xB8
    #if (defined RAS_LIB)
    #define RSA_ACT_AUDIO              0xB9
    #define RSA_ACT_PUSH_TO_TALK       0xBA
    #endif //RAS_LIB
    #define RSA_ACT_APP_END            0xBA
    
    
  9. Add action in key map, so that an action is associated with a button on the remote.
  10. 
    ...
     { RSA_ACT_XMIT, RTI_CERC_RECORD, HID_NONE },                   // 0b00 00 1000   - REC
     { RSA_ACT_XMIT, RTI_CERC_NUM_1, HID_KEYBOARD_1 },              // 0b00 00 1001   - 1
    #if (defined RAS_LIB)
     { RSA_ACT_AUDIO, RTI_CERC_RESERVED_1, HID_NONE },              // 0b00 00 1010   - AV
    #else
     { RSA_ACT_KEY_EX, RTI_CERC_RESERVED_1, HID_NONE },             // 0b00 00 1010   - AV
    #endif //RAS_LIB
     { RSA_ACT_PAIR, RTI_CERC_RESERVED_1, HID_NONE },               // 0b00 00 1100   - RED (K1)
    ...
     { RSA_ACT_UNPAIR, RTI_CERC_RESERVED_1, HID_NONE },             // 0b00 01 1011   - YELLOW (K3)
    #if (defined RAS_LIB)
     { RSA_PUSH_TO_TALK, RTI_CERC_RESERVED_1, HID_NONE },           // 0b00 01 1100   - GREEN (K2)
    #else
     { RSA_ACT_TEST_MODE, RTI_CERC_RESERVED_1, HID_NONE },          // 0b00 01 1100   - GREEN (K2)
    #endif
     { RSA_ACT_XMIT, RTI_CERC_NUM_8, HID_KEYBOARD_8 },              // 0b00 01 1101   - 8
    ...
    
    
  11. Add functions to handle key press, and callback from audio library
  12. 
    #if (defined RAS_LIB)
    static void rsaAudioKeyAction( rsaKeyState_t keyState );
    static void rsaPushToTalkKeyAction( rsaKeyState_t keyState );
    static void rsaAudioToggle(void);
    void RSA_StreamStopped( uint8 status);
    #endif //RAS_LIB
    
    
  13. Add audio key action functions to function array.
  14. 
    const rsaAppActionFn_t rsaAppKeyActions[] =
    {
    ...
      rsaTogglePollAction,
    #if (defined RAS_LIB)
      rsaAudioKeyAction,
      rsaPushToTalkKeyAction
    #endif //RAS_LIB
    
    
  15. Add state variable to track audio state
  16. 
    #ifdef RAS_LIB
    static uint8 rsaAudioState;
    #endif //RAS_LIB
    
    
  17. Initialize audio state when application initializes
  18. 
    void RSA_Init( uint8 taskId )
    {
    ...
    #ifdef RAS_LIB
      rsaAudioState = RSA_STATE_READY;
    #endif //RAS_LIB
    
    
  19. Add STOP_STREAM event handling
  20. 
    uint16 RSA_ProcessEvent( uint8 taskId, uint16 events )
    {
    ...
    #ifdef RAS_LIB
      if (events & RSA_EVT_STOP_STREAM)
      {
        if ( (rsaState == RSA_STATE_STREAM) )
        {
          //Rest the codec to put it in Power down mode
          Hal_codecReset();
          //Stop the MCLK
          Hal_codecMclockStop();
          RAS_Stop(); //==> Lib will call the stop confirmation callback
          
          //Technically, it s not ready, a packet might be pending in the queue...
          //Wait for the callback before chaning state
          //rsaState = RSA_STATE_READY;
        }
        return events ^ RSA_EVT_STOP_STREAM;
      }
    #endif 
    
    
  21. We need all processing that has to do with audio to happen fast. So we use local compile optimization pragmas. Note that this is redundant when we can afford to use speed optimization globally, however it is required when we have to select parts of the code to optimize for speed. When streaming audio we route the send data confirmation to the audio library. Following are the updates required in the RTI_SendDataCnf()
  22. 
    #ifdef RAS_LIB
    #pragma optimize=speed
    #endif
    void RTI_SendDataCnf( rStatus_t status )
    {
    #ifdef RAS_LIB    
      if( (rsaState == RSA_STATE_STREAM))
      {
        RAS_SendDataCnf(status);
      }
    #endif
    
    
  23. Add function to process callback from audio library
  24. 
    #if (defined RAS_LIB)
    void RSA_StreamStopped( uint8 status)
    { 
      rsaState = RSA_STATE_READY;
    
      if(status == 0)
      {
    #if (defined HAL_BUZZER) && (HAL_BUZZER == TRUE)
        /* Tell OSAL to not go to sleep because buzzer uses T3 */
        osal_pwrmgr_task_state( RSA_TaskId, PWRMGR_HOLD );
        
        RSA_PlayTune( RSA_TUNE_END  ); // ring buzzer to signal end
    #endif    
      }
      else
      {
        //Status fail, stop the clock...
        Hal_codecReset();
        //Stop the MCLK
        Hal_codecMclockStop();
        
    #if (defined HAL_BUZZER) && (HAL_BUZZER == TRUE)
        /* Tell OSAL to not go to sleep because buzzer uses T3 */
        osal_pwrmgr_task_state( RSA_TaskId, PWRMGR_HOLD );
    
        RSA_PlayTune( RSA_TUNE_ERROR  ); // ring buzzer to signal end error
    #endif    
      }
      
      rsaAudioState = RSA_STATE_READY;
    }
    #endif // RAS_LIB
    
    
  25. Add function to start/stop audio stream
  26. 
    #if (defined RAS_LIB)
    uint8 globalRsaCalledRAS_Start = FALSE;
    static void rsaAudioToggle(void)
    {
      if(  rsaDestIndex != RTI_INVALID_PAIRING_REF)
      {
        {
          if(rsaState == RSA_STATE_STREAM)          
          {
            if (rsaAudioState == RSA_STATE_STREAM)
            {
              //Rest the codec to put it in Power down mode
              Hal_codecReset();
              //Stop the MCLK
              Hal_codecMclockStop();
              RAS_Stop(); //==> Lib will call the stop confirmation callback
              
              //Technically, it s not ready, a packet might be pending in the queue...
              //Wait for the callback before changing state
              //rsaState = RSA_STATE_READY;
            }
          }
          else if (rsaState == RSA_STATE_READY)
          {
            if (rsaAudioState == RSA_STATE_READY)
            {
              rasCfg_t rasAudioCfg;
              rsaState = RSA_STATE_STREAM;
              
              //First start the MCLK and reset the codec.
              Hal_codecMclockStart(4000);
              Hal_codecReset();
              
              //Configure the codec
    #ifdef CC2533F96_VRC_REVB
              Hal_codecInit16kHz_ADC3101_mic_vrc_diff();    
    #else
              Hal_codecInit16kHz_ADC3101_mic_vrc();    
    #endif            
              //Hal_codecInit16kHz_ADC3101_lineIn_vrc();
              
              //Initialize the Audio Configuration Structure.
              rasAudioCfg.fs       = 16;
              rasAudioCfg.nbBits  =  16;
              rasAudioCfg.format   = 1;
              rasAudioCfg.ras_StreamStopped   = RSA_StreamStopped;
              rsaAudioState = RSA_STATE_STREAM;
              
              globalRsaCalledRAS_Start = TRUE;
              RAS_Start( rsaDestIndex , rasAudioCfg);
              globalRsaCalledRAS_Start = FALSE;
              
              //If the audio needs to run for a specific duration, set a timeout now.
              //if (rasCfg.duration)
              //  osal_start_timerEx(RSA_TaskId, RSA_EVT_STOP_AUDIO_CMD,rasCfg.duration*10 );
            }
          }
        }    
      }  
    }
    #endif // RAS_LIB
    
    

OSAL[edit]

In the OSAL setup code, rsa_osal.c perform the following steps

  1. Include header
  2. 
    #include "ras_lib.h"
    
    
  3. Add RAS_ProcessEvent function to the task processing functions array. Position in array reflects the priority given to the audio task
  4. 
    const pTaskEventHandlerFn tasksArr[] =
    {
      macEventLoop,
      RCN_ProcessEvent,
      RTI_ProcessEvent,
    #ifdef RAS_LIB
      RAS_ProcessEvent,
    #endif //RAS_LIB  
      gdpOriginator_ProcessEvent,
      RSA_ProcessEvent,
      Hal_ProcessEvent
    };
    
    
  5. Add OSAL init function for audio task. Again, order is not random, but reflects task priority
  6. 
    void osalInitTasks( void )
    {
    ...
      RTI_Init( taskID++ );
    #ifdef RAS_LIB
      RAS_Init( taskID++ );
    #endif //RAS_LIB  
      gdpOriginator_Init( taskID++ );
    
    

Driver[edit]

In the main file, rsa_main.c, add hardware initialization steps required for the codec.

  1. Include header
  2. 
    #include "hal_codec.h"
    
    
  3. Call the codec reset functions
  4. 
    #if (defined RAS_LIB)
      Hal_codecResetConfig();
      Hal_codecReset();
    #endif
    
    

In the CODEC driver file hal_codec.c, set global ticks to 0. The buzzer driver has been updated to use a divided global tick source (8MHz). Before starting the codec we must set it back to an undivided clock.

  1. While setting up the master clock, set the global tick speed back to undivided.
  2. 
    void Hal_codecMclockStart( uint16 freq )
    {
    ...
      /* Configure output pin as peripheral since we're using T4 to generate */
      MCLK_SEL |= (uint8)HAL_MCLK_GPIO_PINS;
    
      CLKCONCMD &= (TICKSPD_MASK ^ 0xFF);
      
      T4CTL = divider |
              HAL_T4_TIMER_CTL_CLEAR |
              opmode;
    
    

In the DMA driver file hal_dma.c, add hooks for the audio library.

  1. Include header
  2. 
    #include "ras_lib.h"
    
    
  3. Add RAS_LIB to precompiler clause to enable DMA interrupt, and to implement interrupt handler
  4. 
    void HalDmaInit( void )
    {
    

    ...

    #if (HAL_UART_DMA || \
      ((defined HAL_SPI) && (HAL_SPI == TRUE))  || \
      (defined RAS_LIB)  || \
      ((defined HAL_IRGEN) && (HAL_IRGEN == TRUE)))
     DMAIE = 1;
    #endif
    }
    
    #if (HAL_UART_DMA || \
       ((defined HAL_SPI) && (HAL_SPI == TRUE))  || \
       (defined RAS_LIB)   || \
       ((defined HAL_IRGEN) && (HAL_IRGEN == TRUE)))
    /******************************************************************************
     * @fn      HalDMAInit
    
    
  5. Add call to audio library's DMA interrupt handler
  6. 
    #if (defined RAS_LIB) 
      if ( HAL_DMA_CHECK_IRQ( HAL_DMA_CH_RX ) )
      {
        HAL_DMA_CLEAR_IRQ( HAL_DMA_CH_RX );
        RAS_DmaIsr();
      }
    #endif 
    
    

In the key scanner driver hal_key.c update to support voice remote layout

  1. Voice remote uses P0.7 instead of P1.4 for key scan, so update relevant macros.
  2. 
    #ifdef CC2533F96_VRC_REVB
      //VRC-RevB use P0.7 for key scan.
      #define HAL_KEY_P0_GPIO_PINS  ( HAL_KEY_BIT0 | HAL_KEY_BIT1 | HAL_KEY_BIT2 | HAL_KEY_BIT3 | HAL_KEY_BIT4 | HAL_KEY_BIT7)
    #else
      #define HAL_KEY_P0_GPIO_PINS  ( HAL_KEY_BIT0 | HAL_KEY_BIT1 | HAL_KEY_BIT2 | HAL_KEY_BIT3 | HAL_KEY_BIT4)
    #endif
    ...
    #ifndef CC2533F96_VRC_REVB
      //adv. remote use P1.4 for key scan.
      #define HAL_KEY_P1_GPIO_PINS  ( HAL_KEY_BIT4 )
    #endif
    ...
    #ifdef CC2533F96_VRC_REVB
      //VRC-RevB use P0.7 for key scan.
      #define HAL_KEY_P0_OUTPUT_PINS  ( HAL_KEY_BIT3 | HAL_KEY_BIT4 | HAL_KEY_BIT7)
    #else
      #define HAL_KEY_P0_OUTPUT_PINS  ( HAL_KEY_BIT3 | HAL_KEY_BIT4 )
    #endif
    ...
    #ifndef CC2533F96_VRC_REVB
      #define HAL_KEY_P1_OUTPUT_PINS  ( HAL_KEY_BIT4 )
    #endif
    ...
    #ifdef CC2533F96_VRC_REVB
      #define HAL_KEY_SHIFT_REGISTER_DATA_PIN   P0_7
    #else
      #define HAL_KEY_SHIFT_REGISTER_DATA_PIN   P1_4
    #endif
    
    
  3. In the initialization routine we no longer have to setup Port 1 since no pins are connected anymore
  4. 
    #ifndef CC2533F96_VRC_REVB
      P1SEL &= (uint8) ~HAL_KEY_P1_GPIO_PINS;
    #endif  
    ...
    #ifndef CC2533F96_VRC_REVB
      P1DIR |= (uint8) HAL_KEY_P1_OUTPUT_PINS;
    #endif
    
    

In the accelerometer driver hal_accel.c update to support voice remote layout

  1. Voice remote uses P1.3 instead of P1.2 for accelerometer interrupt and no pin to control power to the accelerometer, so update relevant macros.
  2. 
    #ifdef CC2533F96_VRC_REVB
    //VRC-Rev B: P1.3 used for Accel interrupt
    #define HAL_ACCEL_P1_GPIO_PINS  ( BV(3) )
    /* These defines indicate the direction of each pin */
    #define HAL_ACCEL_P1_INPUT_PINS  ( BV(3) )
    /* Which pins are used for key interrupts */
    #define HAL_ACCEL_P1_INTERRUPT_PINS   ( BV(3) )
    #else
    ...
    /* Which pins are used for key interrupts */
    #define HAL_ACCEL_P1_INTERRUPT_PINS   ( BV(2) )
    ...
    #endif
    
    
  3. Then update initialization code
  4. 
     /* Initialize outputs */
    #ifdef CC2533F96_VRC_REVB
      P1SEL &= (uint8) ~HAL_ACCEL_P1_GPIO_PINS;
      P1DIR &= (uint8) ~HAL_ACCEL_P1_INPUT_PINS;
    #else
    ...
     P1DIR &= (uint8) ~HAL_ACCEL_P1_INPUT_PINS;
    #endif
    
    

In the gyro driver hal_gyro.c update to support voice remote layout

  1. Voice remote uses P1.2 instead of P1.3 for gyro interrupt, and no pin to control power to the gyro, so update relevant macros.
  2. 
    
    1. ifdef CC2533F96_VRC_REVB
    /* The following define which port pins are being used by the gyro */
    #define HAL_GYRO_P0_GPIO_PINS  ( BV( 5 ) )
    #define HAL_GYRO_P1_GPIO_PINS  ( BV( 2 ) )
    /* These defines indicate the direction of each pin */
    #define HAL_GYRO_P0_OUTPUT_PINS  ( BV( 5 ) )
    #define HAL_GYRO_P1_OUTPUT_PINS  ( BV( 2 ) )
    /* Defines for each output pin assignment */
    #define HAL_GYRO_CLKIN_PIN  P0_5
    #define HAL_GYRO_INT_PIN    P1_2
    #else
    ...
    #define HAL_GYRO_INT_PIN    P1_3
    #endif
    
    
  3. Update initialization code to not control power pin, which no longer exist
  4. 
    #ifndef CC2533F96_VRC_REVB
      HAL_GYRO_POWER_PIN = 1;
    #endif