据世卫组织发布的统计公报:目前,全球患有残疾性听力损失约有3.6亿人,占全球人口总量5%。我国是人口大国,同样在全球听力残疾患者数量占比较大的国家,目前国内还有听力残弱患者数量达2780万人。助听器不是万能的,远距离的声音聆听确实要比“原装耳朵”差一些,不能把远距离声音听不清这个锅全部甩给助听器,毕竟这涉及到很多原因:声音能量在传输过程中会自我衰减、助听器的拾音距离有限、传输过程中声音信息被遮挡导致接收到的内容不完全等都会导致助听器佩戴者无法很好的听清楚远距离声音。
     
     RSL10 是一款 Bluetooth 5、多协议无线电片上系统 (SoC),RSL10可支持蓝牙低功耗技术和2.4 GHz专有协议栈,而不会影响功耗,业界最低功耗。双核设计Arm Cortex M3处理器和LPDSP32 DSP核心。Arm Cortex-M3处理器,时钟速度高达48 MHz;LPDSP32:32位双Harvard DSP核心嵌入式数字信号处理器(DSP)支持信号处理密集型应用,为无线通信所需的音频编解码器提供高效支持。
111.jpg
     某品牌助听器,采用安森美Ezairo® 7160 SL, 可实现助听器中的无线联接,是一款可开放编程的、基于 DSP 的混合模块,支持 Bluetooth® 低能耗和其他 2.4 GHz 无线协议。 Ezairo 7160 SL 中器件 Ezairo 7100 数字型号处理器 (DSP): 包括一个高精度、四芯体系结构,提供 375 MIPS 而不会牺牲功耗性能 RSL10 无线电集成电路: 行业内最低功耗的 Bluetooth 5 认证无线传感器,支持业内最低功耗的蓝牙低能耗和专属的 2.4 GHz 协议 EA2M: 2 Mb EEPROM 内存。
   基于安森美蓝牙BLE 5.0的助听器遥控和远程拾音麦克风设计架构图:
1.jpg
    助听器Ezairo® 7160 SLRSL10 无线电集成电路,采用RLS10作为助听器遥控器方案,方面开发。通过RLS10蓝牙将远程麦克风与助听器进行连接,可以满足10米甚至20米的远距离聆听,同时可以调节音量。
   实现蓝牙遥控器的功能。对于这种应用的实际上大体思路有两种方法,方法一:使用蓝牙串口工程,蓝牙串口工程搭建好了数据通道,可以通过 APP 发送指令(类似串口发送 AT 指令),然后后通过 APP 发送的不同指令类型,来实现对硬件设备的无线控制,第二种方法:采用类似蓝牙 LED 服务,建立一个私有任务,通过主机的读写功能,对从机进行数据写入,从而控制从机设备。这种方式实际上是从新搭建一个数据通道。
   关键代码:
  1. static void nus_data_handler(ble_nus_evt_t * p_evt)//串口中断操作
  2. {
  3.     if (p_evt->type == BLE_NUS_EVT_RX_DATA)
  4.     {
  5.         RLS_LOG_DEBUG("Received data from BLE NUS. Writing data on UART.");
  6.         RLS_LOG_HEXDUMP_DEBUG(p_evt->params.rx_data.p_data, p_evt->params.rx_data.length);
  7.                        
  8.                          if((p_evt->params.rx_data.p_data[0]=='A')&&(p_evt->params.rx_data.p_data[1]=='T')&&(p_evt->params.rx_data.p_data[2]=='+'))
  9.                 {
  10.                        
  11.              if(((p_evt->params.rx_data.p_data[3]=='O')||(p_evt->params.rx_data.p_data[3]=='o'))&&((p_evt->params.rx_data.p_data[4]=='N')||(p_evt->params.rx_data.p_data[4]=='n')))  //如果收到的数据为“ON”或者"on"
  12.                 {
  13.                  RLS_gpio_pin_clear(LED_2 );    //工作指示绿灯亮
  14.                  RLS_gpio_pin_set(LED_3);        //工作指示红灯灭
  15.                  states[0]=p_evt->params.rx_data.p_data[0];               //更新要上传的状态数据
  16.                  states[1]=p_evt->params.rx_data.p_data[1];
  17.                  states[2]=0;
  18.                  change_state=1;                  //状态发生变化,马上上传状态一次
  19.                 }
  20.                
  21.                  if(((p_evt->params.rx_data.p_data[3]=='O')||(p_evt->params.rx_data.p_data[3]=='o'))&&((p_evt->params.rx_data.p_data[4]=='F')||(p_evt->params.rx_data.p_data[4]=='f'))&&((p_evt->params.rx_data.p_data[5]=='F')||(p_evt->params.rx_data.p_data[5]=='f')))
  22.                 {
  23.                  //如果收到的数据为“OFF”或者"off"
  24.                  RLS_gpio_pin_clear(LED_3);     //工作指示红灯亮
  25.                  RLS_gpio_pin_set(LED_2);    //工作指示绿灯灭
  26.                  states[0]=p_evt->params.rx_data.p_data[0];             //更新要上传的状态数据
  27.                  states[1]=p_evt->params.rx_data.p_data[1];
  28.                  states[2]=p_evt->params.rx_data.p_data[2];
  29.                  change_state=1;                  //状态发生变化,马上上传状态一次
  30.                 }
  31.         }
  32.         if (p_evt->params.rx_data.p_data[p_evt->params.rx_data.length - 1] == '\r')
  33.         {
  34.             while (app_uart_put('\n') == RLS_ERROR_BUSY);
  35.         }
  36.    
  37.         }
  38. }
  


2.jpg


实现   麦克风远程拾音:
LPDSP32-V3 Block Diagram:

5.jpg

     麦克风远程拾音: RLS10,SDK,对远程麦克风 remote. _mic.很多设计参考:
3.jpg

  1. * ----------------------------------------------------------------------------
  2. * rm_app.c
  3. * - Remote mic application
  4. * ----------------------------------------------------------------------------
  5. * $Revision: 1.12 $
  6. * $Date: 2019/12/27 18:50:38 $
  7. * ------------------------------------------------------------------------- */
  8. #include "app.h"
  9. #include <printf.h>
  10. uint32_t data_rd = 0;
  11. /* For Test */
  12. uint8_t tmp;
  13. uint32_t ascc_cnt, audio_sink_phase_cnt, erraaa = 0;
  14. uint8_t inTempBuffLeft[100]  = {
  15.     0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
  16.     0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf
  17. };
  18. uint8_t inTempBuffRight[100] = {
  19.     0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc,
  20.     0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc
  21. };
  22. uint8_t outTempBuff[100];
  23. uint16_t app_sendCntrRight = 0, app_sendCntrLeft = 0, app_receiveCntr = 0;
  24. uint32_t app_err1 = 0, app_err2 = 0, app_err3 = 0, app_err4 = 0, app_err5 = 0,
  25.          app_err6 = 0, app_err7 = 0;
  26. struct app_env_tag app_env;
  27. const uint8_t coded_sample[4 * 60] = {
  28.     0xb1, 0x5b, 0x5d, 0xdf, 0xef, 0x7b, 0xb7, 0xff, 0x3c, 0xff, 0xbf, 0x3b,
  29.     0xff, 0xcb, 0x5c, 0xb7,
  30.     0xbb, 0x5d, 0xfa, 0xc7, 0x7d, 0xf3, 0xef, 0x7e, 0xbb, 0xd7, 0xbd, 0xff,
  31.     0xe9, 0xff, 0xfb, 0x7f,
  32.     0xe6, 0xdf, 0x59, 0xd5, 0xd6, 0xfd, 0x35, 0xd3, 0xf9, 0x14, 0x9f, 0x64,
  33.     0xf7, 0x9b, 0x55, 0x3f,
  34.     0x99, 0x49, 0xbf, 0xd5, 0x6d, 0xbf, 0xd7, 0x6b, 0x75, 0xbd, 0x7f, 0xb7,
  35.     0xfa, 0xe7, 0xee, 0x32, 0x7a, 0x1a, 0x4e, 0xd7, 0x5e, 0xf7, 0xef, 0x7f,
  36.     0xdf, 0xef, 0xbe, 0x5b,
  37.     0xed, 0xf6, 0xdb, 0xfd, 0xb5, 0xdf, 0x5d, 0xa7, 0xd7, 0x79, 0xb6, 0xfe,
  38.     0x79, 0xfe, 0xbf, 0xef,
  39.     0x7e, 0xfa, 0xbf, 0x7b, 0xfb, 0xcb, 0x5b, 0xfa, 0xd7, 0x3f, 0x76, 0xf7,
  40.     0x77, 0xde, 0xf5, 0xb5,
  41.     0xfd, 0x5d, 0x36, 0x93, 0x6d, 0x76, 0xdb, 0x4f, 0xe5, 0xff, 0x79, 0xfe,
  42.     0x9f, 0xd3, 0x6d, 0x36, 0xda, 0x18, 0x57, 0x47, 0xdd, 0xde, 0xff, 0xd6,
  43.     0xd1, 0xdf, 0xfe, 0xbb,
  44.     0xef, 0xb6, 0xf1, 0xef, 0x2f, 0xdb, 0xe5, 0x7e, 0x5b, 0xfd, 0x65, 0xfd,
  45.     0xff, 0xff, 0xb3, 0xff,
  46.     0xad, 0xed, 0xcd, 0xed, 0xd9, 0xfd, 0xb7, 0x5b, 0x59, 0xb4, 0xfd, 0x6f,
  47.     0xbd, 0xba, 0xdf, 0x3e,
  48.     0xef, 0xcf, 0x7f, 0xfe, 0x7d, 0x77, 0x57, 0x65, 0x24, 0xff, 0x6b, 0xbe,
  49.     0xf5, 0xdb, 0x0c, 0xb4, 0xac, 0x63, 0xa5, 0xdd, 0xf7, 0x5d, 0xef, 0xad,
  50.     0xfb, 0xff, 0xde, 0xfd,
  51.     0xdb, 0x7f, 0xff, 0xd7, 0xfd, 0xff, 0xdf, 0xee, 0xf9, 0xef, 0xfe, 0xfb,
  52.     0xff, 0xef, 0xff, 0xe5,
  53.     0xae, 0xd6, 0xfd, 0xf5, 0xff, 0x6d, 0x76, 0xdb, 0x6d, 0x76, 0xd6, 0x6d,
  54.     0xb4, 0xff, 0x5d, 0x75,
  55.     0xff, 0x59, 0x77, 0xdf, 0x4f, 0xb6, 0xd7, 0xe9, 0x6e, 0x9e, 0x7d, 0xff
  56. };
  57. uint32_t coded_cntr = 0;
  58. void APP_RM_Init(uint8_t side)
  59. {
  60.     struct rm_callback callback;
  61.     uint8_t temp[16] = RM_HOPLIST;
  62.     app_env.rm_link_status              = LINK_DISCONNECTED;
  63.     app_env.rm_lostLink_counter         = 0;
  64.     app_env.rm_unsuccessLink_cunter     = 0;
  65.     app_env.audio_streaming             = 0;
  66.     app_env.rm_param.audioChnl          = side;
  67.     app_env.rm_param.role = RM_SLAVE_ROLE;
  68.     app_env.rm_param.interval_time      = 10000;
  69.     app_env.rm_param.retrans_time       = 5000;
  70.     app_env.rm_param.audio_rate         = 48;
  71.     app_env.rm_param.radio_rate         = 2000;
  72.     app_env.rm_param.scan_time          = 6500;
  73.     app_env.rm_param.preamble           = 0x55;
  74.     app_env.rm_param.accessword         = (0x00cde629 | (0x0d << 24));
  75.     app_env.rm_param.payloadFlowRequest = APP_RM_DATA_REQUEST_TYPE;
  76.     app_env.rm_param.renderDelay        = 200;
  77.     if (app_env.rm_param.payloadFlowRequest == RM_APP_REQUEST)
  78.     {
  79.         app_env.rm_param.preFetchDelay = 1300;
  80.     }
  81.     else
  82.     {
  83.         app_env.rm_param.preFetchDelay = 400;
  84.     }
  85.     app_env.rm_param.pktLostLowThrshld     = 10;
  86.     app_env.rm_param.pktLostHighThrshld    = 200;
  87.     app_env.rm_param.pktLostLowThrshldSlow = 1;
  88.     app_env.rm_param.searchTryCntThrshld   = 20;
  89.     app_env.rm_param.waitCntGranularity    = 200;
  90.     app_env.rm_param.stepSize = 1;
  91.     app_env.rm_param.numChnlInHopList = 7;
  92.     app_env.rm_param.mod_idx  = BLE_MOD_IDX;
  93.     app_env.rm_param.dma_memcpy_num   = MEMCPY_DMA_NUM;
  94.     app_env.rm_param.debug_dio_num[0] = DEBUG_DIO_FIRST;
  95.     app_env.rm_param.debug_dio_num[1] = DEBUG_DIO_SECOND;
  96.     app_env.rm_param.debug_dio_num[2] = 0xff;
  97.     app_env.rm_param.debug_dio_num[3] = 0xff;
  98.     memcpy(app_env.rm_param.hopList, temp, 16);
  99.     callback.trx_event     = RM_Callback_TRX;
  100.     callback.status_update = RM_Callback_StatusUpdate;
  101.     RM_Configure(&app_env.rm_param, callback);
  102.     rm_env.intf.status_update(LINK_DISCONNECTED);
  103. }
  104. uint8_t ptr_right[ENCODED_FRAME_LENGTH];
  105. uint8_t cntr_enc_rm0 = 0, cntr_enc_rm1 = 0;
  106. uint8_t RM_Callback_TRX(uint8_t type, uint8_t *length, uint8_t *ptr)
  107. {
  108.     switch (type)
  109.     {
  110.         case RM_TX_PAYLOAD_READY_LEFT:
  111.         {
  112.         }
  113.         break;
  114.         case RM_TX_PAYLOAD_READY_RIGHT:
  115.         {
  116.         }
  117.         break;
  118.         case RM_RX_TRANSFER_GOODPKT:
  119.         case RM_RX_TRANSFER_BADCRCPKT:
  120.         case RM_RX_TRANSFER_NOPKT:
  121.         {
  122.             if ((*length) == 0)
  123.             {
  124.                 /* PLC should be applied as tx hasn't sent data
  125.                  * for example: repeat previous packet, */
  126.                 memset(outTempBuff, 0xaa, ((app_env.rm_param.audio_rate *
  127.                                             app_env.rm_param.interval_time) /
  128.                                            8000));
  129.                 app_err1++;
  130.             }
  131.             else
  132.             {
  133. #if (OUTPUT_INTRF == SPI_TX_RAW_OUTPUT)
  134.                 memcpy(outTempBuff, ptr, *length);
  135.                 Rendering_func(outTempBuff);
  136. #endif    /* if (OUTPUT_INTRF == SPI_TX_RAW_OUTPUT) */
  137. #if (OUTPUT_INTRF == SPI_TX_CODED_OUTPUT)
  138.                 SPI0_CTRL1->SPI0_CS_ALIAS = SPI0_CS_1_BITBAND;
  139.                 memcpy(outTempBuff, ptr, *length);
  140.                 SPI0_CTRL1->SPI0_CS_ALIAS = SPI0_CS_0_BITBAND;
  141. #if 0
  142.                 Sys_DMA_Set_ChannelDestAddress(TX_DMA_NUM, (uint32_t)ptr);
  143.                 Sys_DMA_ClearChannelStatus(TX_DMA_NUM);
  144.                 Sys_DMA_ChannelEnable(TX_DMA_NUM);
  145. #else    /* if 0 */
  146.                 Sys_DMA_ChannelConfig(
  147.                     TX_DMA_NUM,
  148.                     TX_DMA_SPI,
  149.                     AUDIO_FRAME_SIZE,
  150.                     0,
  151.                     (uint32_t)outTempBuff,
  152.                     (uint32_t)&SPI0->TX_DATA
  153.                     );
  154.                 Sys_DMA_ClearChannelStatus(TX_DMA_NUM);
  155.                 Sys_DMA_ChannelEnable(TX_DMA_NUM);
  156. #endif    /* if 0 */
  157. #endif    /* if (OUTPUT_INTRF == SPI_TX_CODED_OUTPUT) */
  158.                 if (type == RM_RX_TRANSFER_GOODPKT)
  159.                 {
  160.                     if ((app_receiveCntr + 1) != (((outTempBuff[1] << 8) |
  161.                                                    outTempBuff[0])))
  162.                     {
  163.                         app_err2++;
  164.                     }
  165.                     app_receiveCntr = ((outTempBuff[1] << 8) | outTempBuff[0]);
  166.                     if (app_env.rm_param.audioChnl == RM_FIRST_AUDIO_CHANNEL)
  167.                     {
  168.                         if (outTempBuff[20] != 0xaf)
  169.                         {
  170.                             app_err3++;
  171.                         }
  172.                     }
  173.                     else
  174.                     {
  175.                         if (outTempBuff[20] != 0xbc)
  176.                         {
  177.                             app_err3++;
  178.                         }
  179.                     }
  180.                 }
  181.                 else
  182.                 {
  183.                     app_err1++;
  184.                 }
  185.             }
  186.         }
  187.         break;
  188.         case RM_SWPLL_SYNC:
  189.         {
  190.         }
  191.         break;
  192.         default:
  193.         {
  194.         }
  195.         break;
  196.     }
  197.     return (0);
  198. }
  199. uint8_t RM_Callback_StatusUpdate(uint8_t status)
  200. {
  201.     switch (status)
  202.     {
  203.         case LINK_DISCONNECTED:
  204.         {
  205.             PRINTF("__RM_LINK_DISCONNECTED\n");
  206.             /* Stop audio transmission to avoid having annoying noise
  207.              * decide if the number of lost links is large, do an action */
  208. #if (OUTPUT_INTRF == SPI_TX_RAW_OUTPUT && SIMUL != 1)
  209.             NVIC_DisableIRQ(AUDIOSINK_PHASE_IRQn);
  210.             NVIC_DisableIRQ(AUDIOSINK_PERIOD_IRQn);
  211.             /* DMA interrupts */
  212.             NVIC_DisableIRQ(DMA_IRQn(ASRC_IN_IDX));
  213.             /* LPDSP32 interrupt */
  214.             NVIC_DisableIRQ(DSP1_IRQn);
  215.             /* Timer interrupts */
  216.             NVIC_DisableIRQ(TIMER_IRQn(TIMER_REGUL));
  217.             Sys_Timers_Stop(1 << TIMER_REGUL);
  218. #endif    /* if (OUTPUT_INTRF == SPI_TX_RAW_OUTPUT && SIMUL != 1) */
  219.             app_env.rm_lostLink_counter++;
  220.         }
  221.         break;
  222.         case LINK_ESTABLISHMENT_UNSUCCESS:
  223.         {
  224.             app_env.rm_unsuccessLink_cunter++;
  225.         }
  226.         break;
  227.         case LINK_ESTABLISHED:
  228.         {
  229.             PRINTF("__RM_LINK_ESTABLISHED\n");
  230.             /* start audio transmission */
  231. #if (OUTPUT_INTRF == SPI_TX_RAW_OUTPUT && SIMUL != 1)
  232.             asrc_stable     = false;
  233.             cntr_stability  = 0;
  234.             audio_sink_cnt  = 0;
  235.             flag_ascc_phase = false;
  236.             Sys_ASRC_Reset();
  237.             /* ASCC interrupts */
  238.             NVIC_EnableIRQ(AUDIOSINK_PHASE_IRQn);
  239.             NVIC_EnableIRQ(AUDIOSINK_PERIOD_IRQn);
  240.             /* DMA interrupts */
  241.             NVIC_EnableIRQ(DMA_IRQn(ASRC_IN_IDX));
  242.             /* LPDSP32 interrupt */
  243.             NVIC_EnableIRQ(DSP1_IRQn);
  244.             /* Timer interrupts */
  245.             NVIC_EnableIRQ(TIMER_IRQn(TIMER_REGUL));
  246. #endif    /* if (OUTPUT_INTRF == SPI_TX_RAW_OUTPUT && SIMUL != 1) */
  247.         }
  248.         break;
  249.         default:
  250.         {
  251.         }
  252.         break;
  253.     }
  254.     app_env.rm_link_status = status;
  255.     return (0);
  256. }
https://v.youku.com/v_show/id_XNTgyMDA4NTYwMA==.html?spm=a2hbt.13141534.1_2.d_1&scm=20140719.manual.114461.video_XNTgyMDA4NTYwMA==