安森美RSL10开发-ARM-M3


最近开发RSL10的芯片,目前测试下,该平台在低功耗表现出色,双核ARM+DSP,在测试主频6MHz下功耗仅为3mA

资料下载

安森美官网

开发环境配置

以IAR8.32为例,对于IDE的界面就不截图了。
同时官方提供,初始工程配置的引导教程:RSL10_getting_started_guide.pdf

SDK加入

工程目录分配如下:官方的SDK直接拷贝进来,其他工程文件自己组织。
在这里插入图片描述

添加头文件目录

$TOOLKIT_DIR$\CMSIS\Driver\Include
$PROJ_DIR$\ONSemiconductor\RSL10\3.5.285\source\firmware\drivers\dma_driver\include
$PROJ_DIR$\ONSemiconductor\RSL10\3.5.285\source\firmware\drivers\gpio_driver\include
$PROJ_DIR$\ONSemiconductor\RSL10\3.5.285\source\firmware\printf
$PROJ_DIR$\ONSemiconductor\RSL10\3.5.285\source\firmware\rtt
$PROJ_DIR$\ONSemiconductor\RSL10\3.5.285\source\firmware\drivers\i2c_driver\include
$PROJ_DIR$\ONSemiconductor\RSL10\3.5.285\include
$PROJ_DIR$\ONSemiconductor\RSL10\3.5.285\source\firmware\drivers\RTE_config
$PROJ_DIR$\ONSemiconductor\RSL10\3.5.285\source\firmware\drivers\timer_driver\include
$PROJ_DIR$\ONSemiconductor\RSL10\3.5.285\source\firmware\drivers\sai_driver\include
$PROJ_DIR$\ONSemiconductor\RSL10\3.5.285\source\firmware\drivers\usart_driver\include
$PROJ_DIR$\ONSemiconductor\RSL10\3.5.285\source\firmware\drivers\spi_driver\include
$PROJ_DIR$\ONSemiconductor\RSL10\3.5.285\source\firmware\drivers\pwm_driver\include
$PROJ_DIR$\ONSemiconductor\RSL10\3.5.285\source\firmware\flashlib\include
$PROJ_DIR$\ONSemiconductor\RSL10\3.5.285\source\firmware\flashlib\port
$PROJ_DIR$\ONSemiconductor\RSL10\3.5.285\source\firmware\ble_abstraction_layer\ble\include
$PROJ_DIR$\ONSemiconductor\RSL10\3.5.285\include\kernel
$PROJ_DIR$\ONSemiconductor\RSL10\3.5.285\include\bb
$PROJ_DIR$\ONSemiconductor\RSL10\3.5.285\include\ble
$PROJ_DIR$\ONSemiconductor\RSL10\3.5.285\include\ble\profiles

添加宏定义

RSL10_CID=101
_RTE_
CFG_BLE=1
CFG_ALLROLES=1
CFG_CON=8
CFG_APP
CFG_APP_BATT
CFG_ATTC=1
CFG_EMB=1
CFG_HOST=1
CFG_RF_ATLAS=1
CFG_ALLPRF=1
CFG_PRF=1
CFG_NB_PRF=2
CFG_CHNL_ASSESS=1
CFG_SEC_CON=1
CFG_EXT_DB
CFG_PRF_BASC=1

分散加载文件

/* ----------------------------------------------------------------------------
 * Copyright (c) 2019 Semiconductor Components Industries, LLC
 * (d/b/a ON Semiconductor). All Rights Reserved.
 *
 * This code is the property of ON Semiconductor and may not be redistributed
 * in any form without prior written permission from ON Semiconductor. The
 * terms of use and warranty for this code are covered by contractual
 * agreements between ON Semiconductor and the licensee.
 * ----------------------------------------------------------------------------
 * sections.icf
 * - Simple sections load file
 * ----------------------------------------------------------------------------
 * $Revision: 1.1 $
 * $Date: 2019/07/18 15:49:48 $
 * ------------------------------------------------------------------------- */

/* The memory space denoting the maximum possible amount of addressable memory */
define memory Mem with size = 4G;

/* Memory regions in an address space */
define region ROM = Mem:[from 0x00000 size 4K];
/*define region FLASH = Mem:[from 0x0010C800 size 334K];*/
define region FLASH = Mem:[from 0x00100000 size 380K];
define region PRAM = Mem:[from 0x00200000 size 32K];
define region DRAM = Mem:[from 0x20000000 size 24K];
define region DRAM_DSP = Mem:[from 0x20006000 size 48K];
define region DRAM_BB = Mem:[from 0x20012000 size 16K];


/* Create a stack */
define block CSTACK with size = 4K, alignment = 4 { };
define block HEAP with size = 4K, alignment = 4 { };
/* Handle initialization */
do not initialize { section .noinit, section .systemclock };
initialize by copy {readwrite}; /* Initialize RW sections, exclude zero-initialized sections */

/* Place startup code at the start of flash */
place at start of FLASH {readonly object startup_rsl10.o}; 
/* Place code and data */
place in FLASH {readonly}; /* Place constants and initializers: .rodata and .data_init */
place at start of DRAM {section .systemclock};
/*
 * place in DRAM {readwrite};  Place .data, .bss, and .noinit 
 */
place in PRAM {readwrite}; /* Place .data, .bss, and .noinit */
place at end  of DRAM {block HEAP, block CSTACK};
place in PRAM {section .PRAM32Kmemory}; /* Place .PRAM32Kmemory */

添加源文件

启动文件

在这里插入图片描述

库文件

在这里插入图片描述
在这里插入图片描述

调试打印工具

在这里插入图片描述
在这里插入图片描述
使用

#include <printf.h>

PRINTF("RSL10 DEVICE INITIALIZED Version v1.2\r\n");

代码

时钟配置

使用内部RF48Mhz晶振,分频系数为1
请添加图片描述

关于Systick

附图地址:硬件参考手册Page73
在这里插入图片描述
Systick时钟源,由寄存器CLCSOURCE确定
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

以下代码,初始化时钟到48MHz,也可以初始化到8MHz的主频,使用DIO5作为恢复按键,当程序异常跑飞,无法调试下载时,将DIO5接地即可阻塞代码的执行。此时擦除代码,从而恢复正常状态。

/* DIO number that is used for easy re-flashing (recovery mode) */
#define RECOVERY_DIO                    5

/* ----------------------------------------------------------------------------
 * Function      : void Initialize(void)
 * ----------------------------------------------------------------------------
 * Description   : Initialize the system by disabling interrupts, switching to
 *                 the 48 MHz clock.
 * Inputs        : None
 * Outputs       : None
 * Assumptions   : None
 * ------------------------------------------------------------------------- */
static void Initialize(void)
{
  /* Mask all interrupts */
  __set_PRIMASK(PRIMASK_DISABLE_INTERRUPTS);

  /* Disable all existing interrupts, clearing all pending source */
  Sys_NVIC_DisableAllInt();
  Sys_NVIC_ClearAllPendingInt();

  /* Test DIO12 to pause the program to make it easy to re-flash */
  DIO->CFG[RECOVERY_DIO] = DIO_MODE_INPUT  | DIO_WEAK_PULL_UP |
                           DIO_LPF_DISABLE | DIO_6X_DRIVE;
  while (DIO_DATA->ALIAS[RECOVERY_DIO] == 0);
    
  /* Prepare the 48 MHz crystal
   * Start and configure VDDRF */
  ACS_VDDRF_CTRL->ENABLE_ALIAS = VDDRF_ENABLE_BITBAND;
  ACS_VDDRF_CTRL->CLAMP_ALIAS  = VDDRF_DISABLE_HIZ_BITBAND;

  /* Wait until VDDRF supply has powered up */
  while (ACS_VDDRF_CTRL->READY_ALIAS != VDDRF_READY_BITBAND);
  
  /* Disable RF TX power amplifier supply voltage and
  * connect the switched output to VDDRF regulator */
  ACS_VDDPA_CTRL->ENABLE_ALIAS = VDDPA_DISABLE_BITBAND;
  ACS_VDDPA_CTRL->VDDPA_SW_CTRL_ALIAS    = VDDPA_SW_VDDRF_BITBAND;
    
  /* Enable RF power switches */
  SYSCTRL_RF_POWER_CFG->RF_POWER_ALIAS   = RF_POWER_ENABLE_BITBAND;

  /* Remove RF isolation */
  SYSCTRL_RF_ACCESS_CFG->RF_ACCESS_ALIAS = RF_ACCESS_ENABLE_BITBAND;

  /* Set radio clock accuracy in ppm */
  BLE_DeviceParam_Set_ClockAccuracy(RADIO_CLOCK_ACCURACY);
    
  /* Start the 48 MHz oscillator without changing the other register bits */
  RF->XTAL_CTRL = ((RF->XTAL_CTRL & ~XTAL_CTRL_DISABLE_OSCILLATOR) |
                   XTAL_CTRL_REG_VALUE_SEL_INTERNAL);

#if USE_HI_FQ_16K_AUDIO_SAMPLE  
  /* Enable 48 MHz oscillator divider at desired prescale value */
  RF_REG2F->CK_DIV_1_6_CK_DIV_1_6_BYTE = CK_DIV_1_6_PRESCALE_1_BYTE;
#else
  /* Enable 48 MHz oscillator divider at desired prescale value ->8MHz*/
  RF_REG2F->CK_DIV_1_6_CK_DIV_1_6_BYTE = CK_DIV_1_6_PRESCALE_6_BYTE;
#endif  
  
  /* Wait until 48 MHz oscillator is started */
  while (RF_REG39->ANALOG_INFO_CLK_DIG_READY_ALIAS !=
         ANALOG_INFO_CLK_DIG_READY_BITBAND);

  /* Switch to 48 MHz oscillator clock */
  Sys_Clocks_SystemClkConfig(JTCK_PRESCALE_1   |
                             EXTCLK_PRESCALE_1 |
                             SYSCLK_CLKSRC_RFCLK);

  /* Configure clock dividers */
#if USE_HI_FQ_16K_AUDIO_SAMPLE  
  CLK->DIV_CFG0 = (SLOWCLK_PRESCALE_48 | BBCLK_PRESCALE_6 |
                   USRCLK_PRESCALE_2);
  CLK->DIV_CFG2 = (CPCLK_PRESCALE_8 | DCCLK_PRESCALE_12);
#else
  CLK->DIV_CFG0 = (SLOWCLK_PRESCALE_8 | BBCLK_PRESCALE_1 |
                   USRCLK_PRESCALE_1);
  CLK->DIV_CFG2 = (CPCLK_PRESCALE_8 | DCCLK_PRESCALE_2);
#endif
  BBIF->CTRL    = (BB_CLK_ENABLE | BBCLK_DIVIDER_8 | BB_WAKEUP);
  
  /* Stop masking interrupts */
  __set_PRIMASK(PRIMASK_ENABLE_INTERRUPTS);
  __set_FAULTMASK(FAULTMASK_ENABLE_INTERRUPTS);
}

定时器操作

依赖TIMER_RSLxx.c
Systick启动

static uint32_t Timer_Port_TimeMS  = 0;
static uint32_t Timer_Port_TimeSec = 0;

/*初始化Systick,设置事件回调*/
Driver_TIMER.Initialize(TIMER_Port_SignalEvent);

/*启动Systick*/
Driver_TIMER.Start(TIMER_SYSTICK);

/**
  ******************************************************************
  * @brief   定时事件回调
  * @param   [in]None.
  * @return  None.
  * @author  aron566
  * @version V1.0
  * @date    2021-07-20
  ******************************************************************
  */
static void TIMER_Port_SignalEvent(uint32_t event)
{ 
  if(TIMER_SYSTICK_EVENT & event)
  {
    Timer_Port_IRQHandler();
  } 
}

/**
  ******************************************************************
  * @brief   定时器中断回调
  * @param   [in]None
  * @return  None.
  * @author  aron566
  * @version V1.0
  * @date    2021-01-13
  ******************************************************************
  */
static inline void Timer_Port_IRQHandler(void)
{
  Timer_Port_TimeMS++;
  if(Timer_Port_TimeMS == 1000)
  {
    Timer_Port_TimeMS = 0;
    Timer_Port_TimeSec++;
  }
}

串口操作

依赖USART_RSLxx.c,同时需要在RTE_Device.h定义好串口的RX与TX脚,不要与其他脚冲突。

static uint8_t RX_Buff_Temp[256];

/*初始化,设置事件回调*/
Driver_USART0.Initialize(RSL10_USART_SignalEvent);
/*启动接收*/
Driver_USART0.Receive(RX_Buff_Temp, 1);

/************************************************************
  * @brief   RSL10串口事件回调
  * @param   event 事件.
  * @return  None
  * @author  aron566
  * @date    2020/7/19
  * @version v1.0
  * @note    @@
  ***********************************************************/
static void RSL10_USART_SignalEvent(uint32_t event)
{
  if(event & ARM_USART_EVENT_SEND_COMPLETE)
  {
    /*发送完成回调*/
  }
  if(event & ARM_USART_EVENT_RECEIVE_COMPLETE)
  {
    /*接收到数据*/
  }
}

I2C操作

依赖I2C_RSLxx.c,同时需要在RTE_Device.h定义好串口的SDA与SCL脚,不要与其他脚冲突。

这里的地址需要按照标准I2C的格式7bit或者10bit方式写入

在这里插入图片描述
如上图这样的地址作为本机地址:那么从机地址就是0x06 Slave_Addr = 0x06

  /* Initialize i2c, register callback function */
  Driver_I2C0.Initialize(I2C_EventCallback);
  
  /*配置I2C自身地址*/
  Driver_I2C0.Control(ARM_I2C_OWN_ADDRESS, Slave_Addr);
  
  /* Wait for new transfer as slave */
  Driver_I2C0.SlaveReceive(I2C_RX_Buf, SLAVE_RX_SIZE_MIN);

PDM操作

DMA使用注意

在使用DMA音频传输需要注意格式问题即配置问题,DMA最小的step步长32bit,当配置为LSB对齐,数据长度为16bit音频数据,配置如下

方向:外设到内存,内存存储区为DMIC0_Audio_Data,取16bit宽度(这里无需在意DMA最小的step步长32bit,因为他是静态外设地址),DMA需要配置为:从外设取16bit数据宽度,目标存储宽度32bit(为了配合OD的DMA 内存到外设 最小的step步长32bit,所以存储宽度为32bit)

static int16_t DMIC0_Audio_Data[320] = {0};
static int16_t OD_Audio_Data[320] = {0};

/*音频DMA配置*/
#if USE_AUDIO_DMA_MODE
// <h>Source configuration
// ===============================
//
//   <o>Source target
//       <0x0=> I2C    <0x1=> SPI0
//       <0x2=> SPI1   <0x3=> PCM
//       <0x4=> UART   <0x5=> ASRC
//       <0x6=> PBUS   <0x7=> DMIC
//       <0x8=> MEMORY
//   <i> Defines the source target
//   <i> Default: MEMORY
#ifndef DMIC0_DMA_SRC_SEL_DEFAULT
 #define DMIC0_DMA_SRC_SEL_DEFAULT   7
#endif
//   <o>Step mode
//       <0x0=> Increment
//       <0x1=> Decrement
//       <0x2=> Static
//   <i> Defines if the source address should be incremented / decremented during the trasnfer
//   <i> Default: Increment
#ifndef DMIC0_DMA_SRC_STEP_MODE_DEFAULT
 #define DMIC0_DMA_SRC_STEP_MODE_DEFAULT   2
#endif
//   <o>Step size
//       <0x0=> 1 x 32bits
//       <0x1=> 2 x 32bits
//       <0x2=> 3 x 32bits
//       <0x3=> 4 x 32bits
//   <i> Defines the source address step size. Valid only if increment / decrement step mode was selected
//   <i> Default: 1 x 32bit
#ifndef DMIC0_DMA_SRC_STEP_SIZE_DEFAULT
 #define DMIC0_DMA_SRC_STEP_SIZE_DEFAULT   0
#endif
//   <o>Word size
//       <0x3=> 4bits
//       <0x0=> 8bits
//       <0x1=> 16bits
//       <0x2=> 32bits
//   <i> Defines the single source word size
//   <i> Default: 8bits
#ifndef DMIC0_DMA_SRC_WORD_SIZE_DEFAULT
 #define DMIC0_DMA_SRC_WORD_SIZE_DEFAULT   1/**< 搬运宽度*/
#endif
// </h>
// <h>Destination configuration
// ===============================
//
//   <o>Destination target
//       <0x0=> I2C    <0x1=> SPI0
//       <0x2=> SPI1   <0x3=> PCM
//       <0x4=> UART   <0x5=> ASRC
//       <0x6=> PBUS   <0x7=> DMIC
//       <0x8=> MEMORY
//   <i> Defines the destination target
//   <i> Default: MEMORY
#ifndef DMIC0_DMA_DST_SEL_DEFAULT
 #define DMIC0_DMA_DST_SEL_DEFAULT   8
#endif
//   <o>Step mode
//       <0x0=> Increment
//       <0x1=> Decrement
//       <0x2=> Static
//   <i> Defines if the destination address should be incremented / decremented during the trasnfer
//   <i> Default: Increment
#ifndef DMIC0_DMA_DST_STEP_MODE_DEFAULT
 #define DMIC0_DMA_DST_STEP_MODE_DEFAULT   0
#endif
//   <o>Step size
//       <0x0=> 1 x 32bits
//       <0x1=> 2 x 32bits
//       <0x2=> 3 x 32bits
//       <0x3=> 4 x 32bits
//   <i> Defines the destination address step size. Valid only if increment / decrement step mode was selected
//   <i> Default: 1 x 32bit
#ifndef DMIC0_DMA_DST_STEP_SIZE_DEFAULT
 #define DMIC0_DMA_DST_STEP_SIZE_DEFAULT   0
#endif
//   <o>Word size
//       <0x3=> 4bits
//       <0x0=> 8bits
//       <0x1=> 16bits
//       <0x2=> 32bits
//   <i> Defines the single destination word size
//   <i> Default: 8bits
#ifndef DMIC0_DMA_DST_WORD_SIZE_DEFAULT
 #define DMIC0_DMA_DST_WORD_SIZE_DEFAULT   2/**< 数据存放格式*/
#endif
// </h>
//   <o>Data transfer mode
//       <0x0=> Repeat
//       <0x1=> Single
//   <i> Defines if the transfer should be executed once or repeatedly
//   <i> Default: Single
#ifndef DMIC0_DMA_DATA_MODE_DEFAULT
 #define DMIC0_DMA_DATA_MODE_DEFAULT   0
#endif
//   <o>Data endianness
//       <0x0=> Little Endian
//       <0x1=> Big endian
//   <i> Defines the data bytes order to be used
//   <i> Default: Little Endian
#ifndef DMIC0_DMA_BYTE_ORDER_DEFAULT
 #define DMIC0_DMA_BYTE_ORDER_DEFAULT   0
#endif
//   <o>Channel priority
//       <0x0=> 0  <0x1=> 1
//       <0x2=> 2  <0x3=> 3
//   <i> Defines the channel priority
//   <i> Default: 0
#ifndef DMIC0_DMA_CHANNEL_PRIORITY_DEFAULT
 #define DMIC0_DMA_CHANNEL_PRIORITY_DEFAULT   0
#endif
// <h>Interrupt priority configuration
// ===============================
//
//   <o>Pre-empt priority <0-0x7>
//   <i> Defines the pre-empt priority
//   <i> Default: 0
#ifndef DMIC0_DMA_INT_PREEMPT_PRI
 #define DMIC0_DMA_INT_PREEMPT_PRI   0
#endif
//   <o>Subgroup priority <0-0x7>
//   <i> Defines the subgroup priority
//   <i> Default: 0
#ifndef DMIC0_DMA_INT_SUBGRP_PRI
 #define DMIC0_DMA_INT_SUBGRP_PRI   0
#endif
// </h>
// </e>
// </e>

// <h>Source configuration
// ===============================
//
//   <o>Source target
//       <0x0=> I2C    <0x1=> SPI0
//       <0x2=> SPI1   <0x3=> PCM
//       <0x4=> UART   <0x5=> ASRC
//       <0x6=> PBUS   <0x7=> DMIC
//       <0x8=> MEMORY
//   <i> Defines the source target
//   <i> Default: MEMORY
#ifndef OD_DMA_SRC_SEL_DEFAULT
 #define OD_DMA_SRC_SEL_DEFAULT   8
#endif
//   <o>Step mode
//       <0x0=> Increment
//       <0x1=> Decrement
//       <0x2=> Static
//   <i> Defines if the source address should be incremented / decremented during the trasnfer
//   <i> Default: Increment
#ifndef OD_DMA_SRC_STEP_MODE_DEFAULT
 #define OD_DMA_SRC_STEP_MODE_DEFAULT   0
#endif
//   <o>Step size
//       <0x0=> 1 x 32bits
//       <0x1=> 2 x 32bits
//       <0x2=> 3 x 32bits
//       <0x3=> 4 x 32bits
//   <i> Defines the source address step size. Valid only if increment / decrement step mode was selected
//   <i> Default: 1 x 32bit
#ifndef OD_DMA_SRC_STEP_SIZE_DEFAULT
 #define OD_DMA_SRC_STEP_SIZE_DEFAULT   0
#endif
//   <o>Word size
//       <0x3=> 4bits
//       <0x0=> 8bits
//       <0x1=> 16bits
//       <0x2=> 32bits
//   <i> Defines the single source word size
//   <i> Default: 8bits
#ifndef OD_DMA_SRC_WORD_SIZE_DEFAULT
 #define OD_DMA_SRC_WORD_SIZE_DEFAULT   2/**< 源数据格式固定*/
#endif
// </h>
// <h>Destination configuration
// ===============================
//
//   <o>Destination target
//       <0x0=> I2C    <0x1=> SPI0
//       <0x2=> SPI1   <0x3=> PCM
//       <0x4=> UART   <0x5=> ASRC
//       <0x6=> PBUS   <0x7=> DMIC
//       <0x8=> MEMORY
//   <i> Defines the destination target
//   <i> Default: MEMORY
#ifndef OD_DMA_DST_SEL_DEFAULT
 #define OD_DMA_DST_SEL_DEFAULT   7
#endif
//   <o>Step mode
//       <0x0=> Increment
//       <0x1=> Decrement
//       <0x2=> Static
//   <i> Defines if the destination address should be incremented / decremented during the trasnfer
//   <i> Default: Increment
#ifndef OD_DMA_DST_STEP_MODE_DEFAULT
 #define OD_DMA_DST_STEP_MODE_DEFAULT   2
#endif
//   <o>Step size
//       <0x0=> 1 x 32bits
//       <0x1=> 2 x 32bits
//       <0x2=> 3 x 32bits
//       <0x3=> 4 x 32bits
//   <i> Defines the destination address step size. Valid only if increment / decrement step mode was selected
//   <i> Default: 1 x 32bit
#ifndef OD_DMA_DST_STEP_SIZE_DEFAULT
 #define OD_DMA_DST_STEP_SIZE_DEFAULT   0
#endif
//   <o>Word size
//       <0x3=> 4bits
//       <0x0=> 8bits
//       <0x1=> 16bits
//       <0x2=> 32bits
//   <i> Defines the single destination word size
//   <i> Default: 8bits
#ifndef OD_DMA_DST_WORD_SIZE_DEFAULT
 #define OD_DMA_DST_WORD_SIZE_DEFAULT   1/**< 每传输宽度*/
#endif
// </h>
//   <o>Data transfer mode
//       <0x0=> Repeat
//       <0x1=> Single
//   <i> Defines if the transfer should be executed once or repeatedly
//   <i> Default: Single
#ifndef OD_DMA_DATA_MODE_DEFAULT
 #define OD_DMA_DATA_MODE_DEFAULT   0
#endif
//   <o>Data endianness
//       <0x0=> Little Endian
//       <0x1=> Big endian
//   <i> Defines the data bytes order to be used
//   <i> Default: Little Endian
#ifndef OD_DMA_BYTE_ORDER_DEFAULT
 #define OD_DMA_BYTE_ORDER_DEFAULT   0
#endif
//   <o>Channel priority
//       <0x0=> 0  <0x1=> 1
//       <0x2=> 2  <0x3=> 3
//   <i> Defines the channel priority
//   <i> Default: 0
#ifndef OD_DMA_CHANNEL_PRIORITY_DEFAULT
 #define OD_DMA_CHANNEL_PRIORITY_DEFAULT   0
#endif
// <h>Interrupt priority configuration
// ===============================
//
//   <o>Pre-empt priority <0-0x7>
//   <i> Defines the pre-empt priority
//   <i> Default: 0
#ifndef OD_DMA_INT_PREEMPT_PRI
 #define OD_DMA_INT_PREEMPT_PRI   0
#endif
//   <o>Subgroup priority <0-0x7>
//   <i> Defines the subgroup priority
//   <i> Default: 0
#ifndef OD_DMA_INT_SUBGRP_PRI
 #define OD_DMA_INT_SUBGRP_PRI   0
#endif
// </h>
// </e>
// </e>

#endif ///< USE_AUDIO_DMA_MODE  

OD操作

Flash操作

RSL10的Flash操作需要注意,操作的字节对齐到32位的整数倍。

在这里插入图片描述

因为工程使用FAL分区进行管理Flash,这边直接给出接口代码。
依赖官方文件:drv_flash.c、rsl10_flash_rom.h、rsl10_sys_flash.c

/**
 *  @file fal_flash_rsl10h7_port.c
 *
 *  @date 2021-07-31
 *
 *  @author aron566
 *
 *  @copyright aron566.
 *
 *  @brief FLASH FAL操作接口 User main memory
 *
 *  @details BANK1 RANGE:0x00100000 - 0x0015FFFF TOTAL_SIZE:384KB 芯片信息位于rsl10_map.h
 *           
 *           write granularities : 32bit
 *
 *  @version V1.0
 */
#include <fal.h>
#include <string.h>
#include <rsl10.h>
#include "drv_flash.h"
#include "rsl10_flash.h"
#include "Timer_Port.h"   
   
/* base address of the flash sectors */
#define BANK_1_ADDR_FLASH_SECTOR_0      ((uint32_t)0x00100000) /* Base address of Sector 0, 2 K bytes*/
#define BANK_1_ADDR_FLASH_SECTOR_1      ((uint32_t)0x00100800) /* Base address of Sector 1, 2 K bytes*/
#define BANK_1_ADDR_FLASH_SECTOR_2      ((uint32_t)0x00101000) /* Base address of Sector 2, 2 K bytes*/

#ifndef FLASH_PAGE_SIZE
  #define FLASH_PAGE_SIZE               2*1024U
#endif

#define FLASH_PAGE_0_ADDR               BANK_1_ADDR_FLASH_SECTOR_0	/* 物理flash原始起始页地址 */
#define FLASH_START_PAGE_ADDR	          BANK_1_ADDR_FLASH_SECTOR_0	/* 分区表起始地址 */
#define CURRENT_PART_START_PAGE	        ((FLASH_START_PAGE_ADDR-FLASH_PAGE_0_ADDR)/FLASH_PAGE_SIZE)	/* 当前分区实际物理起始页 */
#define FLASH_PAGE_NUM_MAX		          (384/2U)

/*拷贝完成标识*/
static volatile uint8_t Sys_Flash_Copy_Complete = 0;

/* ----------------------------------------------------------------------------
 * Function      : void FLASH_COPY_IRQHandler(void)
 * ----------------------------------------------------------------------------
 * Description   : Set a status flag to indicate the flash copier
 *                 operation is complete.
 * Inputs        : None
 * Outputs       : None
 * Assumptions   : None
 * ------------------------------------------------------------------------- */
void FLASH_COPY_IRQHandler(void)
{
  Sys_Flash_Copy_Complete = 1;
}

uint8_t fal_port_get_copy_state(void)
{
  return Sys_Flash_Copy_Complete;
}

void fal_port_reset_copy_state(void)
{
  Sys_Flash_Copy_Complete = 0;
}

/**
 * Get the sector of a given address
 *
 * @param address flash address
 *
 * @return The sector of a given address
 */
static uint32_t rsl10_get_sector(uint32_t Startaddress ,size_t size ,uint32_t *get_pages)
{
		/*记录起始页与结束页*/
    uint32_t Startpage = 0,Endpage = 0;
		/*搜索完成标记*/
		uint8_t start_page_flag = 0,end_page_flag = 0;
		/*计算起始地址所在页*/
		if(Startaddress >= rsl10_onchip_flash.addr)
		{
      for(uint32_t i = 0; i < FLASH_PAGE_NUM_MAX; i++)
      {
        /*计算首地址所在页*/
        if(start_page_flag == 0)
        {
          if((i*FLASH_PAGE_SIZE+FLASH_PAGE_0_ADDR+FLASH_PAGE_SIZE-1) >= Startaddress)
          {
            log_i("first erase page:%d",i);
            Startpage = i;
            start_page_flag = 1;
          }
        }
        /*计算尾地址所在页*/
        if(end_page_flag == 0)
        {
          if((i*FLASH_PAGE_SIZE+FLASH_PAGE_0_ADDR+FLASH_PAGE_SIZE-1) >= (Startaddress+size-1))
          {
            log_i("end erase page:%d",i);
            Endpage = i;
            end_page_flag = 1;
            break;
          }
        }
      }
		}
		else
		{
				/*地址非法*/
				*get_pages = 0;
				return Startpage;
		}
		/*计算地址范围内的页数*/
		*get_pages = Endpage-Startpage+1;
    /*get sector num*/
    return Startpage;
    /*get addr*/
//    return Startpage*FLASH_PAGE_SIZE+FLASH_PAGE_0_ADDR;
}

/**
 * Get the sector size
 *
 * @param sector sector
 *
 * @return sector size
 */
static uint32_t rsl10_get_sector_size(uint32_t pages) 
{
	return pages*FLASH_PAGE_SIZE;	//!< 2K一页			
}

/**
 * Get the bankx
 *
 * @param addr
 *
 * @return bank num
 */
static uint8_t rsl10_get_addr_bank(uint32_t addr)
{
  (void)(addr);
  return 0;
}

static int init(void)
{
  /* Enable the flash copier interrupt */
  NVIC_EnableIRQ(FLASH_COPY_IRQn);
  return 0;
}

static int read(long offset, uint8_t *buf, size_t size)
{
    uint32_t addr = rsl10_onchip_flash.addr + offset;
    uint8_t temp_buf[sizeof(int)] = {0};
    uint32_t copy_size = size/sizeof(int);
    
    uint32_t Time_Sec = Timer_Port_Get_Current_Time(TIMER_SEC);
    fal_port_reset_copy_state();
    Sys_Flash_Copy(addr, (uint32_t)buf, copy_size, COPY_TO_32BIT);
    
    //wait ok
    while(Sys_Flash_Copy_Complete == 0)
    {
      if((Timer_Port_Get_Current_Time(TIMER_SEC) - Time_Sec) > 10)
      {
        return -1;
      }
    }
    uint32_t copy_size_min = copy_size * sizeof(int) >= size?0:size - copy_size * sizeof(int);
    if(copy_size_min == 0)
    {
      return size;
    }
    
    Time_Sec = Timer_Port_Get_Current_Time(TIMER_SEC);
    fal_port_reset_copy_state();
    Sys_Flash_Copy(addr + copy_size * sizeof(int), (uint32_t)temp_buf, 1, COPY_TO_32BIT);
    
    //wait ok
    while(Sys_Flash_Copy_Complete == 0)
    {
      if((Timer_Port_Get_Current_Time(TIMER_SEC) - Time_Sec) > 10)
      {
        return -1;
      }
    }
    memmove(buf + copy_size * sizeof(int), temp_buf, size - copy_size * 4);
    return size;
}

static int write(long offset, const uint8_t *buf, size_t size)
{
    uint32_t addr = rsl10_onchip_flash.addr + offset;
    const size_t once_write_size = sizeof(int)*2;
    uint8_t write_buf[sizeof(int)*2] = {0};
    size_t wr_size = 0;
    bool ret = 0;
    
    /*once write 64bits*/
    Drv_Flash_Unlock();
    size_t write_cnt_max = (((size/once_write_size)*once_write_size) < size)?(size/once_write_size)+1:(size/once_write_size);
    for(size_t i = 0; i < write_cnt_max; i++)
    {
      /*检查已写入长度*/
      wr_size = (((i+1)*once_write_size) > size)?(size-(i*once_write_size)):once_write_size;
      memmove(write_buf, buf+(i*once_write_size), wr_size);
      ret = Drv_Flash_Program(addr+(i*once_write_size), (const uint32_t *)write_buf);
      if(ret == false)
      {
        log_i("write error");
        return -1;
      }        
      memset(write_buf, 0xFF, once_write_size);
    }
    Drv_Flash_Lock();
    return size;
}

static int erase(long offset, size_t size)
{
    uint32_t flash_status = FLASH_ERR_NONE;
    size_t erased_size = 0;
    
    uint32_t addr = rsl10_onchip_flash.addr + offset;
    uint32_t erasepages = 0;
    /* start erase */
    Drv_Flash_Unlock();
    
    /*循环擦除页地址*/
    uint32_t Sector = rsl10_get_sector(addr ,size ,&erasepages);
    log_i("***Total Erasepages %u****", erasepages);
    for(uint32_t index = 0; index < erasepages; index++)
    {
      Sector = Sector>=FLASH_PAGE_NUM_MAX?Sector-FLASH_PAGE_NUM_MAX:Sector;
      
      log_i("erase page:0x%02X,PAGES:%d BANK:%u", Sector, 1, rsl10_get_addr_bank(addr + FLASH_PAGE_SIZE*index));
      
      flash_status = Drv_Flash_Erase(addr + FLASH_PAGE_SIZE*index);
      log_i("addr 0x%08X", addr + FLASH_PAGE_SIZE*index);
      if(flash_status == false)
      {
        log_i("erase error");
        return -1;
      }
      Sector++;
    }
    
    erased_size += rsl10_get_sector_size(erasepages);
    log_i("erase size:%d", erased_size);

    Drv_Flash_Lock();
    
    return size;
}

const struct fal_flash_dev rsl10_onchip_flash =
{
    .name       = "rsl10_onchip",
    .addr       = FLASH_PAGE_0_ADDR,
    .len        = FLASH_PAGE_SIZE*FLASH_PAGE_NUM_MAX,
    .blk_size   = FLASH_PAGE_SIZE,
    .ops        = {init, read, write, erase},
    .write_gran = 32
};

BLE配置

BLE内核由官方封装精简后打包成库文件,所以这部分代码看不到,而且必须使用他的事件库内核

工程需要包含几个BLE库文件
在这里插入图片描述

时钟配置

/**
  ******************************************************************
  * @brief   初始化时钟、BLE协议栈、消息处理内核
  * @param   [in]None.
  * @return  None.
  * @author  aron566
  * @version v1.0
  * @date    2021/8/12
  ******************************************************************
  */
static inline void BLE_Port_Clock_Init(void)
{
  /* Configure the current trim settings for VCC, VDDA */
  ACS_VCC_CTRL->ICH_TRIM_BYTE  = VCC_ICHTRIM_16MA_BYTE;
  ACS_VDDA_CP_CTRL->PTRIM_BYTE = VDDA_PTRIM_16MA_BYTE;
  
  /* Disable RF TX power amplifier supply voltage and
  * connect the switched output to VDDRF regulator */
  ACS_VDDPA_CTRL->ENABLE_ALIAS = VDDPA_DISABLE_BITBAND;
  ACS_VDDPA_CTRL->VDDPA_SW_CTRL_ALIAS    = VDDPA_SW_VDDRF_BITBAND;
  
  /* Set radio clock accuracy in ppm */
  BLE_DeviceParam_Set_ClockAccuracy(RADIO_CLOCK_ACCURACY);
  
  /*8MHz / 8*/
  BBIF->CTRL    = (BB_CLK_ENABLE | BBCLK_DIVIDER_8 | BB_WAKEUP);
  
  /* Seed the random number generator */
  srand(1);

  /* Initialize the kernel and Bluetooth stack */
  Kernel_Init(0);
  BLE_InitNoTL(0);

  /* Set radio output power of RF */
  Sys_RFFE_SetTXPower(OUTPUT_POWER_DBM);

  /* Enable Bluetooth related interrupts */
  NVIC->ISER[1] = (NVIC_BLE_CSCNT_INT_ENABLE      |
                   NVIC_BLE_SLP_INT_ENABLE        |
                   NVIC_BLE_RX_INT_ENABLE         |
                   NVIC_BLE_EVENT_INT_ENABLE      |
                   NVIC_BLE_CRYPT_INT_ENABLE      |
                   NVIC_BLE_ERROR_INT_ENABLE      |
                   NVIC_BLE_GROSSTGTIM_INT_ENABLE |
                   NVIC_BLE_FINETGTIM_INT_ENABLE  |
                   NVIC_BLE_SW_INT_ENABLE);  
}

术语

在阅读代码中,熟悉常用的术语简写,有助于理解代码。

简称全名描述
BASSBattery Service Server电池服务
DISS / DISDevice Information Service Server设备信息服务
Advadvertising广播
GAPMGAP managerGAP 层
BDBond绑定
NBNumber数量
PRFProfile配置文件
STDstandard标准
SVCservice服务
INDindication指示
conidxConnection index连接号

关于消息ID

1、发送消息

/// Builds the task identifier from the type and the index of that task.
#define KE_BUILD_ID(type, index) ( (ke_task_id_t)(((index) << 8)|(type)) )
/* ----------------------------------------------------------------------------
 * Function      : int GAPC_ConnectionReqInd(ke_msg_idd_t const msg_id,
 *                                           struct gapc_connection_req_ind
 *                                           const *param,
 *                                           ke_task_id_t const dest_id,
 *                                           ke_task_id_t const src_id)
 * ----------------------------------------------------------------------------
 * Description   : Handle connection indication message received from GAP
 * controller
 * Inputs        : - msg_id     - Kernel message ID number
 *                 - param      - Message parameters in format of
 *                                struct gapc_connection_req_ind
 *                 - dest_id    - Destination task ID number
 *                 - src_id     - Source task ID number
 * Outputs       : return value - Indicate if the message was consumed;
 *                                compare with KE_MSG_CONSUMED
 * Assumptions   : None
 * ------------------------------------------------------------------------- */
int GAPC_ConnectionReqInd(ke_msg_id_t const msg_id,
                          struct gapc_connection_req_ind const *param,
                          ke_task_id_t const dest_id,
                          ke_task_id_t const src_id)
{
	ble_env.conidx = KE_IDX_GET(src_id);
	
	/* Send connection confirmation */
	struct gapc_connection_cfm *cfm = KE_MSG_ALLOC(GAPC_CONNECTION_CFM,
	                      KE_BUILD_ID(TASK_GAPC, ble_env.conidx), TASK_APP,
	                      gapc_connection_cfm);
	/* Send the message */
	ke_msg_send(cfm);     
}                 

在上方的函数中,发送消息,首先申请了一块内存,依据存放不同消息,这块内存大小不一,格式统一:消息ID 、发送的地址:事件ID包含连接号,事件来源,消息体

2、接收消息

注意接收内核的消息在参数src_id会带有conidx信息,而应用层发出的消息src_id为TASK_APP

以GAPC层消息ID为例,可以看到消息ID的枚举类型,是以TASK_FIRST_MSG(TASK_ID_GAPC)为起始。
rwip_task.h中定义了TASK_ID_GAPC数值为14

/// Build the first message ID of a task. (in fact a ke_msg_id_t)
#define TASK_FIRST_MSG(task) ((uint16_t)((task) << 8))

所以任务的流转:先使用KE_IDX_GET(msg_id) 获取TASK_ID_GAPC 数值知道它是哪一层的消息

/// Retrieves task index number from task id.
#define KE_IDX_GET(ke_task_id) (((ke_task_id) >> 8) & 0xFF)

再前往那一层去处理消息msg_handler.c

/* ----------------------------------------------------------------------------
 * Function      : int MsgHandler_Notify(ke_msg_id_t const msg_id,
 *                               void const *param, ke_task_id_t const dest_id,
 *                               ke_task_id_t const src_id)
 * ----------------------------------------------------------------------------
 * Description   : Search the lists and call back the functions associated with
 *                 the msg_id, following the priority order (HIGH to LOW). This
 *                 function was designed to be used as the default handler of
 *                 the kernel and shall NOT be called directly by the
 *                 application. To notify an event, the application should
 *                 enqueue a message in the kernel, in order to avoid chaining
 *                 the context of function calls (stack overflow).
 * Inputs        : msg_id   - A task identifier, such as TASK_ID_GAPM
 *                            or a message identifier, such as GAPM_CMP_EVT;
 *                 param    - Message parameter
 *                 dest_id  - destination task
 *                 src_id   - source task
 * Outputs       : None
 * Assumptions   : None
 * ------------------------------------------------------------------------- */
int MsgHandler_Notify(ke_msg_id_t const msg_id, void *param,
                      ke_task_id_t const dest_id, ke_task_id_t const src_id)
{
    MsgHandler_t *tmp = msgHandlerHead;
    uint8_t task_id = KE_IDX_GET(msg_id);

    /* First notify abstraction layer handlers */
    switch(task_id)
    {
        case TASK_ID_GAPC:
            GAPC_MsgHandler(msg_id, param, dest_id, src_id);
            break;
        case TASK_ID_GAPM:
            GAPM_MsgHandler(msg_id, param, dest_id, src_id);
            break;
        case TASK_ID_GATTC:
            GATTC_MsgHandler(msg_id, param, dest_id, src_id);
            break;
        case TASK_ID_GATTM:
            GATTM_MsgHandler(msg_id, param, dest_id, src_id);
            break;
#if RTE_BLE_L2CC_ENABLE
        case TASK_ID_L2CC:
			L2CC_MsgHandler(msg_id, param, dest_id, src_id);
			break;
#endif /* RTE_BLE_L2CC_ENABLE */
    }

    /* Notify subscribed application/profile handlers */
    while(tmp)
    {
        /* If message ID matches or the handler should be called for all
         * messages of this task type */
        if((tmp->msg_id == msg_id) || (tmp->msg_id == task_id))
        {
            tmp->callback(msg_id, param, dest_id, src_id);
        }
        tmp = tmp->next;
    }
    return KE_MSG_CONSUMED;
}
/// GAP Controller Task messages
enum gapc_msg_id
{
    /* Default event */
    /// Command Complete event
    GAPC_CMP_EVT = TASK_FIRST_MSG(TASK_ID_GAPC),

    /* Connection state information */
    /// Indicate that a connection has been established
    GAPC_CONNECTION_REQ_IND,
    /// Set specific link data configuration.
    GAPC_CONNECTION_CFM,

    /// Indicate that a link has been disconnected
    GAPC_DISCONNECT_IND,

    /* Link management command */
    /// Request disconnection of current link command.
    GAPC_DISCONNECT_CMD,

    /* Peer device info */
    /// Retrieve information command
    GAPC_GET_INFO_CMD,
    /// Peer device attribute DB info such as Device Name, Appearance or Slave Preferred Parameters
    GAPC_PEER_ATT_INFO_IND,
    /// Indication of peer version info
    GAPC_PEER_VERSION_IND,
    /// Indication of peer features info
    GAPC_PEER_FEATURES_IND,
    /// Indication of ongoing connection RSSI
    GAPC_CON_RSSI_IND,

    /* Device Name Management */
    /// Peer device request local device info such as name, appearance or slave preferred parameters
    GAPC_GET_DEV_INFO_REQ_IND,
    /// Send requested info to peer device
    GAPC_GET_DEV_INFO_CFM,
    /// Peer device request to modify local device info such as name or appearance
    GAPC_SET_DEV_INFO_REQ_IND,
    /// Local device accept or reject device info modification
    GAPC_SET_DEV_INFO_CFM,

    /* Connection parameters update */
    /// Perform update of connection parameters command
    GAPC_PARAM_UPDATE_CMD,
    /// Request of updating connection parameters indication
    GAPC_PARAM_UPDATE_REQ_IND,
    /// Master confirm or not that parameters proposed by slave are accepted or not
    GAPC_PARAM_UPDATE_CFM,
    /// Connection parameters updated indication
    GAPC_PARAM_UPDATED_IND,

    /* Bonding procedure */
    /// Start Bonding command procedure
    GAPC_BOND_CMD,
    /// Bonding requested by peer device indication message.
    GAPC_BOND_REQ_IND,
    /// Confirm requested bond information.
    GAPC_BOND_CFM,
    /// Bonding information indication message
    GAPC_BOND_IND,

    /* Encryption procedure */
    /// Start Encryption command procedure
    GAPC_ENCRYPT_CMD,
    /// Encryption requested by peer device indication message.
    GAPC_ENCRYPT_REQ_IND,
    /// Confirm requested Encryption information.
    GAPC_ENCRYPT_CFM,
    /// Encryption information indication message
    GAPC_ENCRYPT_IND,

    /* Security request procedure */
    /// Start Security Request command procedure
    GAPC_SECURITY_CMD,
    /// Security requested by peer device indication message
    GAPC_SECURITY_IND,

    /* Signature procedure */
    /// Indicate the current sign counters to the application
    GAPC_SIGN_COUNTER_IND,

    /* Device information */
    /// Indication of ongoing connection Channel Map
    GAPC_CON_CHANNEL_MAP_IND,


    /* Deprecated */
    /// Deprecated messages
    GAPC_DEPRECATED_0,
    GAPC_DEPRECATED_1,
    GAPC_DEPRECATED_2,
    GAPC_DEPRECATED_3,
    GAPC_DEPRECATED_4,
    GAPC_DEPRECATED_5,
    GAPC_DEPRECATED_6,
    GAPC_DEPRECATED_7,
    GAPC_DEPRECATED_8,
    GAPC_DEPRECATED_9,

    /* LE Ping */
    /// Update LE Ping timeout value
    GAPC_SET_LE_PING_TO_CMD,
    /// LE Ping timeout indication
    GAPC_LE_PING_TO_VAL_IND,
    /// LE Ping timeout expires indication
    GAPC_LE_PING_TO_IND,

    /* LE Data Length extension*/
    /// LE Set Data Length Command
    GAPC_SET_LE_PKT_SIZE_CMD,
    /// LE Set Data Length Indication
    GAPC_LE_PKT_SIZE_IND,

    /* Secure Connections */
    /// Request to inform the remote device when keys have been entered or erased
    GAPC_KEY_PRESS_NOTIFICATION_CMD,
    /// Indication that a KeyPress has been performed on the peer device.
    GAPC_KEY_PRESS_NOTIFICATION_IND,

    /* LE PHY update */
    /// Set the PHY configuration for current active link
    GAPC_SET_PHY_CMD,
    /// Active link PHY configuration. Triggered when configuration is read or during an update.
    GAPC_LE_PHY_IND,

    /* Connection parameters update - cont */
    /// Set the preferred slave latency (for slave only, with RW controller)
    GAPC_SET_PREF_SLAVE_LATENCY_CMD,

    // ---------------------- INTERNAL API ------------------------
    /* Internal messages for timer events, not part of API*/
    /// Signature procedure
    GAPC_SIGN_CMD,
    /// Signature result
    GAPC_SIGN_IND,

    /// Parameter update procedure timeout indication
    GAPC_PARAM_UPDATE_TO_IND,
    /// Pairing procedure timeout indication
    GAPC_SMP_TIMEOUT_TIMER_IND,
    /// Pairing repeated attempts procedure timeout indication
    GAPC_SMP_REP_ATTEMPTS_TIMER_IND,

    GAPC_SET_MAX_RX_SIZE_AND_TIME_CMD,
};

比如收到了GAPC_GET_DEV_INFO_REQ_IND请求,消息ID来自与GAPC层,那么我们需要将设备信息返回:调用void GAPC_GetDevInfoCfm(uint8_t conidx, uint8_t req, const union gapc_dev_info_val* dat) dat就是我们要返回的数据,函数内会打包成内核消息给蓝牙协议栈,最终发送出去。

conidx需要调用uint8_t conidx = KE_IDX_GET(src_id);获取

调试出现的问题

在调试模式下,运行此处代码,会解锁失败

/* ----------------------------------------------------------------------------
 * Function      : unsigned NVR2_WriteEnable(bool enable)
 * ----------------------------------------------------------------------------
 * Description   : Enable/Disable writing to NVR2
 * Inputs        : - enable    - Enable writing when true, disable otherwise
 * Outputs       : None
 * Assumptions   : Function should cause a watchdog reset in case of error
 * ------------------------------------------------------------------------- */
void NVR2_WriteEnable(bool enable)
{
    /* Lock or unlock NVR2 region */
    FLASH->NVR_CTRL = NVR2_WRITE_ENABLE;
    FLASH->NVR_WRITE_UNLOCK = enable ? FLASH_NVR_KEY : 0;

    /* Check the lock/unlock operation result */
    bool NVR2_unlocked = (FLASH->IF_STATUS & 0x3FF) == 0x20;

    /* Error checking: this application needs to write in flash. If an error
     * occurred while locking/unlocking NVR2, wait for a watchdog reset */
    if (NVR2_unlocked != enable)
    {
        /* Disable all interrupts and clear any pending interrupts */
        Sys_NVIC_DisableAllInt();
        Sys_NVIC_ClearAllPendingInt();
        //printf("[%s][%s][%s]error application needs to write in flash.", __FUNCTION__, __FILE__, __LINE__);
        while (1)
        {
            /* Wait for Watchdog Reset to Occur */
            __ASM("nop");
        }
    }
}

icf文件修改

/* The memory space denoting the maximum possible amount of addressable memory */
define memory Mem with size = 4G;

/* Memory regions in an address space */
define region ROM = Mem:[from 0x00000 size 4K];

define symbol __ICFEDIT_region_FLASH_start__ = 0x00100000;
define symbol __ICFEDIT_region_FLASH_end__ = __ICFEDIT_region_FLASH_start__+384*1024-1;
define region FLASH = Mem:[from __ICFEDIT_region_FLASH_start__ to __ICFEDIT_region_FLASH_end__];
define region FLASH_NVR_1 = Mem:[from 0x00080000 size 2K];
define region FLASH_NVR_2 = Mem:[from 0x00080800 size 2K];

define region PRAM = Mem:[from 0x00200000 size 32K];

define region PRAM_DSP = Mem:[from 0x00220000 size 40K];/*if use dsp just only for dsp*/

define region DRAM = Mem:[from 0x20000000 size 24K];
define region DRAM_DSP = Mem:[from 0x20006000 size 46K];
/*define region DRAM = Mem:[from 0x20000000 size 32K];
define region DRAM_DSP = Mem:[from 0x20008000 size 38K];*/

define region DRAM_DSP_SHARE = Mem:[from 0x20011800 size 2K];/*for dsp*/
define region DRAM_BB = Mem:[from 0x20012000 size 16K];

/* Create a stack */
define block CSTACK with size = 3K, alignment = 4 { };
define block HEAP with size = 3K, alignment = 4 { };
/* Handle initialization */
do not initialize { section .noinit, section .systemclock };
initialize by copy {readwrite}; /* Initialize RW sections, exclude zero-initialized sections */

/* Place startup code at the start of flash */
place at start of FLASH {readonly object startup_rsl10.o}; 
/* Place code and data */
place in FLASH {readonly}; /* Place constants and initializers: .rodata and .data_init */
/*place at end of FLASH {readonly section .dsp};*/
place in FLASH {readonly section .dsp};

place at start of DRAM {section .systemclock};

place in DRAM_DSP_SHARE {section .shared};/*for dsp*/

place in DRAM_DSP {readwrite}; /* Place .data, .bss, and .noinit */
place in DRAM {section .data, section .noinit, section .bss};
place at end of DRAM {block HEAP, block CSTACK};

place in PRAM {section .PRAM32Kmemory}; /* Place .PRAM32Kmemory */

define exported symbol FLASH_APP_Start_Addr = __ICFEDIT_region_FLASH_start__;

BLE-Asha样本工程移植进IAR

1、添加工程文件
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
2、增加接口文件

/**
 *  @file BLE_Port.c
 *
 *  @date 2021/8/5
 *
 *  @author aron566
 *
 *  @copyright aron566.
 *
 *  @brief 蓝牙驱动
 *
 *  @details 
 *
 *  @version v1.0
 */
/** Includes -----------------------------------------------------------------*/
/* Private includes ----------------------------------------------------------*/
#include "BLE_Port.h"
#include <rsl10.h>
#include <rsl10_protocol.h>
#include <ble_gap.h>
#include <ble_gatt.h>
/*电量服务*/
#include <ble_bass.h>
#include <app_bass.h>

#include <ble_diss.h>

/*助听器*/
#include <ble_asha.h>

#include <msg_handler.h>
#include <printf.h>
/* use C compiler ------------------------------------------------------------*/
#ifdef __cplusplus ///<use C compiler
extern "C" {
#endif
/** Private typedef ----------------------------------------------------------*/

/** Private macros -----------------------------------------------------------*/
#define APP_IDX_MAX                     BLE_CONNECTION_MAX /* Number of APP Task Instances */

#define APP_BLE_DEV_PARAM_SOURCE        FLASH_PROVIDED_or_DFLT /* or APP_PROVIDED  */

/* If APP_BD_ADDRESS_TYPE == GAPM_CFG_ADDR_PUBLIC and APP_DEVICE_PARAM_SRC == FLASH_PROVIDED_or_DFLT
 * the bluetooth address is loaded from FLASH NVR3. Otherwise, this address is used. */
#define APP_BD_ADDRESS_TYPE              GAPM_CFG_ADDR_PRIVATE /* or GAPM_CFG_ADDR_PUBLIC*/
#define APP_BD_ADDRESS                   { 0x94, 0x11, 0x11, 0xff, 0xbb, 0xC2 }
#define APP_NB_PEERS                     8 /* 1-8 */


#define OUTPUT_POWER_DBM                0  /* RF output power in dBm */
#define RADIO_CLOCK_ACCURACY            20 /* RF Oscillator accuracy in ppm */


#define UART_TX_BUFFER_SIZE             100

/* Keyboard UART CLI input codes */
#define KEY_ARROW_UP                    65
#define KEY_ARROW_DOWN                  66
#define KEY_ENTER                       13

/* Maximum number of devices in scan list */
#define ADV_REPORT_LIST_MAX             30

/* Set scan interval to 62.5ms and scan window to 50% of the interval */
#define SCAN_INTERVAL                   100
#define SCAN_WINDOW                     50

/* Timeout to update the UART CLI */
#define SCAN_UART_CLI_TIMEOUT_MS        300
#define START_CONNECTION_CMD_TIMEOUT_MS 3000


/* The number of standard profiles and custom services added in this application */
#define APP_NUM_STD_PRF                 2
#define APP_NUM_CUSTOM_SVC              0

/* Advertising data is composed by device name and company id */
#define APP_DEVICE_NAME_DEFAULT         "ZX-Test"
/* Maximum length for the device name.
 * This is limited by GAP_MAX_NAME_SIZE during the stack build. */
#define APP_DEVICE_NAME_MAXLEN          0x20

/*广播数据*/
/* Advertising data is composed by device name and company id */
#define APP_DEVICE_NAME                 "ZX-Test"

#define APP_DEVICE_NAME_LEN             (sizeof(APP_DEVICE_NAME) - 1)

/*SERVICE 0000ff00-0000-1000-8000-00805f9b34fb*/
/*NOTIFY 0000ff01-0000-1000-8000-00805f9b34fb*/
/*WRITE 0000ff01-0000-1000-8000-00805f9b34fb*/

/* Manufacturer info (ON SEMICONDUCTOR Company ID) */
#define APP_COMPANY_ID                  {0x62, 0x3}
#define APP_COMPANY_ID_LEN              2

#define APP_DEVICE_APPEARANCE_DEFAULT   0
#define APP_PREF_SLV_MIN_CON_INTERVAL   8
#define APP_PREF_SLV_MAX_CON_INTERVAL   10
#define APP_PREF_SLV_LATENCY            0
#define APP_PREF_SLV_SUP_TIMEOUT        200

/* --------------------------------------------------------------------------
 *  Device Information used for Device Information Server Service (DISS)
 * ----------------------------------------------------------------------- */
/* Manufacturer Name Value */
#define APP_DIS_MANUFACTURER_NAME       ("dev_name")
#define APP_DIS_MANUFACTURER_NAME_LEN   (8)

/* Model Number String Value */
#define APP_DIS_MODEL_NB_STR            ("RW-BLE-1.0")
#define APP_DIS_MODEL_NB_STR_LEN        (10)

/* Serial Number */
#define APP_DIS_SERIAL_NB_STR           ("1.0.0.0-LE")
#define APP_DIS_SERIAL_NB_STR_LEN       (10)

/* Firmware Revision */
#define APP_DIS_FIRM_REV_STR            ("1.0.2")
#define APP_DIS_FIRM_REV_STR_LEN        (5)

/* System ID Value - LSB -> MSB */
#define APP_DIS_SYSTEM_ID               ("\x12\x34\x56\xFF\xFE\x9A\xBC\xDE")
#define APP_DIS_SYSTEM_ID_LEN           (8)

/* Hardware Revision String */
#define APP_DIS_HARD_REV_STR            ("1.0.0")
#define APP_DIS_HARD_REV_STR_LEN        (5)

/* Software Revision String */
#define APP_DIS_SW_REV_STR              ("1.0.0")
#define APP_DIS_SW_REV_STR_LEN          (5)

/* IEEE */
#define APP_DIS_IEEE                    ("\xFF\xEE\xDD\xCC\xBB\xAA")
#define APP_DIS_IEEE_LEN                (6)

/**
 * PNP ID Value - LSB -> MSB
 *      Vendor ID Source : 0x02 (USB Implementerӳ Forum assigned Vendor ID value)
 *      Vendor ID : 0x1057      (ON Semiconductor)
 *      Product ID : 0x0040
 *      Product Version : 0x0300
 */

#define APP_DIS_PNP_ID               ("\x02\x57\x10\x40\x00\x00\x03")
#define APP_DIS_PNP_ID_LEN           (7)
#define APP_DIS_FEATURES             (DIS_ALL_FEAT_SUP)

/* Application-provided IRK */
#define APP_IRK                         { 0x01, 0x23, 0x45, 0x68, 0x78, 0x9a, \
                                          0xbc, 0xde, 0x01, 0x23, 0x45, 0x68, \
                                          0x78, 0x9a, 0xbc, 0xde }

/* Application-provided CSRK */
#define APP_CSRK                        { 0x01, 0x23, 0x45, 0x68, 0x78, 0x9a, \
                                          0xbc, 0xde, 0x01, 0x23, 0x45, 0x68, \
                                          0x78, 0x9a, 0xbc, 0xde }

/* Application-provided private key */
#define APP_PRIVATE_KEY                 { 0xEC, 0x89, 0x3C, 0x11, 0xBB, 0x2E, \
                                          0xEB, 0x5C, 0x80, 0x88, 0x63, 0x57, \
                                          0xCC, 0xE2, 0x05, 0x17, 0x20, 0x75, \
                                          0x5A, 0x26, 0x3E, 0x8D, 0xCF, 0x26, \
                                          0x63, 0x1D, 0x26, 0x0B, 0xCE, 0x4D, \
                                          0x9E, 0x07 }

/* Application-provided public key X */
#define APP_PUBLIC_KEY_X                { 0x56, 0x09, 0x79, 0x1D, 0x5A, 0x5F, \
                                          0x4A, 0x5C, 0xFE, 0x89, 0x56, 0xEC, \
                                          0xE6, 0xF7, 0x92, 0x21, 0xAC, 0x93, \
                                          0x99, 0x10, 0x51, 0x82, 0xF4, 0xDD, \
                                          0x84, 0x07, 0x50, 0x99, 0xE7, 0xC2, \
                                          0xF1, 0xC8 }

/* Application-provided public key Y */
#define APP_PUBLIC_KEY_Y                { 0x40, 0x84, 0xB4, 0xA6, 0x08, 0x67, \
                                          0xFD, 0xAC, 0x81, 0x5D, 0xB0, 0x41, \
                                          0x27, 0x75, 0x9B, 0xA7, 0x92, 0x57, \
                                          0x0C, 0x44, 0xB1, 0x57, 0x7C, 0x76, \
                                          0x5B, 0x56, 0xF0, 0xBA, 0x03, 0xF4, \
                                          0xAA, 0x67 }

/* PEriod that only clients that were previously bonded can connect */
#define APP_WHITELIST_PERIOD_S          10


/*蓝牙助听器*/
/* ASHA implementation-specific definitions */
#define APP_ASHA_HI_SYNC_ID             {0x62, 0x03, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}
#define APP_ASHA_DEVICE_CAPABILITIES    (ASHA_CAPABILITIES_MONAURAL | ASHA_CAPABILITIES_SIDE)
#define APP_ASHA_SUPPORTED_CODECS       ASHA_CODEC_ID_G722_16KHZ
#define APP_ASHA_RENDER_DELAY           0 //0ms
#define APP_ASHA_PREPARATION_DELAY      0 //0ms
#define APP_ASHA_FEATURE_MAP            ASHA_FEATURE_MAP_LE_COC_SUPPORTED
#define APP_ASHA_VERSION                0x01




/** Private constants --------------------------------------------------------*/
static const struct ke_msg_handler appm_default_state[] =
{
    { KE_MSG_DEFAULT_HANDLER, (ke_msg_func_t)MsgHandler_Notify }
};

/* Use the state and event handler definition for all states. */
static const struct ke_state_handler appm_default_handler
    = KE_STATE_HANDLER(appm_default_state);

/* Defines a place holder for all task instance's state */
ke_state_t appm_state[APP_IDX_MAX];

static const struct ke_task_desc TASK_DESC_APP = {
    NULL,       &appm_default_handler,
    appm_state, 0,
    APP_IDX_MAX
};

const struct ReadOnlyProperties_t ashaReadOnlyProperties = {
    .version = APP_ASHA_VERSION,
    .deviceCapabilities = APP_ASHA_DEVICE_CAPABILITIES,
    .hiSyncId = APP_ASHA_HI_SYNC_ID,
    .featureMap = APP_ASHA_FEATURE_MAP,
    .renderDelay = APP_ASHA_RENDER_DELAY,
    .preparationDelay = APP_ASHA_PREPARATION_DELAY, //TODO: change to reserved
    .codecIDs = APP_ASHA_SUPPORTED_CODECS,
};
/** Public variables ---------------------------------------------------------*/

/* Device Information structure initialization, includes length and data string */
const struct DISS_DeviceInfo_t deviceInfo =
{
    .MANUFACTURER_NAME  = {.len = APP_DIS_MANUFACTURER_NAME_LEN, .data = (uint8_t*) APP_DIS_MANUFACTURER_NAME},
    .MODEL_NB_STR       = {.len = APP_DIS_MODEL_NB_STR_LEN, .data = (uint8_t*) APP_DIS_MODEL_NB_STR},
    .SERIAL_NB_STR      = {.len = APP_DIS_SERIAL_NB_STR_LEN, .data = (uint8_t*) APP_DIS_SERIAL_NB_STR},
    .FIRM_REV_STR       = {.len = APP_DIS_FIRM_REV_STR_LEN, .data = (uint8_t*) APP_DIS_FIRM_REV_STR},
    .SYSTEM_ID          = {.len = APP_DIS_SYSTEM_ID_LEN, .data = (uint8_t*) APP_DIS_SYSTEM_ID},
    .HARD_REV_STR       = {.len = APP_DIS_HARD_REV_STR_LEN, .data = (uint8_t*) APP_DIS_HARD_REV_STR},
    .SW_REV_STR         = {.len = APP_DIS_SW_REV_STR_LEN, .data = (uint8_t*) APP_DIS_SW_REV_STR},
    .IEEE               = {.len = APP_DIS_IEEE_LEN, .data = (uint8_t*) APP_DIS_IEEE},
    .PNP                = {.len = APP_DIS_PNP_ID_LEN, .data = (uint8_t*) APP_DIS_PNP_ID},
};

struct gapm_set_dev_config_cmd devConfigCmd =
{
    .operation = GAPM_SET_DEV_CONFIG,
    .role = GAP_ROLE_PERIPHERAL,
    .renew_dur = GAPM_DEFAULT_RENEW_DUR,
    .addr.addr = APP_BD_ADDRESS,
    .irk.key = APP_IRK,
    .addr_type = APP_BD_ADDRESS_TYPE,
#ifdef SECURE_CONNECTION
    .pairing_mode = (GAPM_PAIRING_SEC_CON | GAPM_PAIRING_LEGACY),
#else
    .pairing_mode = GAPM_PAIRING_LEGACY,
#endif
    .gap_start_hdl = GAPM_DEFAULT_GAP_START_HDL,
    .gatt_start_hdl = GAPM_DEFAULT_GATT_START_HDL,
    .att_and_ext_cfg = GAPM_DEFAULT_ATT_CFG,
    .sugg_max_tx_octets = GAPM_DEFAULT_TX_OCT_MAX,
    .sugg_max_tx_time = GAPM_DEFAULT_TX_TIME_MAX,
    .max_mtu = GAPM_DEFAULT_MTU_MAX,
    .max_mps = GAPM_DEFAULT_MPS_MAX,
    .max_nb_lecb = L2C_CONNECTION_MAX,
    .audio_cfg = GAPM_DEFAULT_AUDIO_CFG,
    .tx_pref_rates = GAP_RATE_LE_1MBPS,
    .rx_pref_rates = GAP_RATE_LE_1MBPS
};

/*广播模式*/
struct gapm_start_advertise_cmd advertiseCmd =
{
    .op = {
        .code = GAPM_ADV_UNDIRECT,
        .addr_src = GAPM_STATIC_ADDR,
        .state = 0
    },
    .intv_min = GAPM_DEFAULT_ADV_INTV_MIN,
    .intv_max = GAPM_DEFAULT_ADV_INTV_MAX,
    .channel_map = GAPM_DEFAULT_ADV_CHMAP,
    .info.host = {
        .mode = GAP_GEN_DISCOVERABLE,
        .adv_filt_policy = ADV_ALLOW_SCAN_ANY_CON_ANY
        /* ADV_DATA and SCAN_RSP data are set in APP_BLE_Initialize() */
    }
};

/*设备名称信息*/
const union gapc_dev_info_val getDevInfoCfmName =
{
    .name.length = APP_DEVICE_NAME_LEN,
    .name.value  = {APP_DEVICE_NAME}
};

/*设备外观图标默认为0,非通用设备*/
const union gapc_dev_info_val getDevInfoCfmAppearance =
{
    .appearance = APP_DEVICE_APPEARANCE_DEFAULT
};

/*通讯时延参数*/
const union gapc_dev_info_val getDevInfoCfmSlvParams =
{
    .slv_params = {APP_PREF_SLV_MIN_CON_INTERVAL,
                   APP_PREF_SLV_MAX_CON_INTERVAL,
                   APP_PREF_SLV_LATENCY,
                   APP_PREF_SLV_SUP_TIMEOUT}
};

/*设备配置信息集合*/
const union gapc_dev_info_val* getDevInfoCfm[] =
{
    [GAPC_DEV_NAME] = &getDevInfoCfmName,
    [GAPC_DEV_APPEARANCE] = &getDevInfoCfmAppearance,
    [GAPC_DEV_SLV_PREF_PARAMS] = &getDevInfoCfmSlvParams
};

/** Private variables --------------------------------------------------------*/

/** Private function prototypes ----------------------------------------------*/

/** Private user code --------------------------------------------------------*/

/** Private application code -------------------------------------------------*/
/*******************************************************************************
*
*       Static code
*
********************************************************************************
*/

/**
  ******************************************************************
  * @brief   初始化时钟
  * @param   [in]None.
  * @return  None.
  * @author  aron566
  * @version v1.0
  * @date    2021/8/12
  ******************************************************************
  */
static inline void BLE_Port_Clock_Init(void)
{
  /* Configure the current trim settings for VCC, VDDA */
  ACS_VCC_CTRL->ICH_TRIM_BYTE  = VCC_ICHTRIM_16MA_BYTE;
  ACS_VDDA_CP_CTRL->PTRIM_BYTE = VDDA_PTRIM_16MA_BYTE;
  
  /* Disable RF TX power amplifier supply voltage and
  * connect the switched output to VDDRF regulator */
  ACS_VDDPA_CTRL->ENABLE_ALIAS = VDDPA_DISABLE_BITBAND;
  ACS_VDDPA_CTRL->VDDPA_SW_CTRL_ALIAS    = VDDPA_SW_VDDRF_BITBAND;
  
  /* Set radio clock accuracy in ppm */
  BLE_DeviceParam_Set_ClockAccuracy(RADIO_CLOCK_ACCURACY);
  
  /*8MHz / 8*/
  BBIF->CTRL    = (BB_CLK_ENABLE | BBCLK_DIVIDER_8 | BB_WAKEUP);
  
  /* Seed the random number generator */
  srand(1);

  /* Initialize the kernel and Bluetooth stack */
  Kernel_Init(0);
  BLE_InitNoTL(0);

  /* Set radio output power of RF */
  Sys_RFFE_SetTXPower(OUTPUT_POWER_DBM);

  /* Create the application task handler */
  ke_task_create(TASK_APP, &TASK_DESC_APP);

  /* Enable Bluetooth related interrupts */
  NVIC->ISER[1] = (NVIC_BLE_CSCNT_INT_ENABLE      |
                   NVIC_BLE_SLP_INT_ENABLE        |
                   NVIC_BLE_RX_INT_ENABLE         |
                   NVIC_BLE_EVENT_INT_ENABLE      |
                   NVIC_BLE_CRYPT_INT_ENABLE      |
                   NVIC_BLE_ERROR_INT_ENABLE      |
                   NVIC_BLE_GROSSTGTIM_INT_ENABLE |
                   NVIC_BLE_FINETGTIM_INT_ENABLE  |
                   NVIC_BLE_SW_INT_ENABLE);  
}


/* ----------------------------------------------------------------------------
 * Function      : void BASS_Setup(void)
 * ----------------------------------------------------------------------------
 * Description   : Configure the Battery Service Server
 * Inputs        : None
 * Outputs       : None
 * Assumptions   : None
 * ------------------------------------------------------------------------- */
static void BASS_Setup(void)
{
    BASS_Initialize(APP_BAS_NB, APP_BASS_ReadBatteryLevel);
    BASS_NotifyOnBattLevelChange(TIMER_SETTING_S(1));     /* Periodically monitor the battery level. Only notify changes */
    APP_BASS_SetBatMonAlarm(BATMON_SUPPLY_THRESHOLD_CFG); /* BATMON alarm configuration */
}

/* ----------------------------------------------------------------------------
 * Function      : void DISS_Setup(void)
 * ----------------------------------------------------------------------------
 * Description   : Configure the Device Information Service Server
 * Inputs        : None
 * Outputs       : None
 * Assumptions   : None
 * ------------------------------------------------------------------------- */
/**
 * @brief Configure the Device Information Service Server
 */
static void DISS_Setup(void)
{
    DISS_Initialize(APP_DIS_FEATURES, (const struct DISS_DeviceInfo_t*) &deviceInfo);
}

/**
  ******************************************************************
  * @brief   设置广播数据
  * @param   [in]None
  * @return  None.
  * @author  aron566
  * @version v1.0
  * @date    2021/8/24
  ******************************************************************
  */
static void APP_SetAdvScanData(void)
{
  uint8_t devName[]   = APP_DEVICE_NAME;
  uint8_t asha_uuid[] = ASHA_SERVICE_UUID;
  uint8_t companyID[] = APP_COMPANY_ID;

  /* Set advertising data as device name + ASHA UUID */
  advertiseCmd.info.host.adv_data_len = 0;
  
  /*设置完整设备名*/
  GAPM_AddAdvData(GAP_AD_TYPE_COMPLETE_NAME, devName,
                  APP_DEVICE_NAME_LEN, advertiseCmd.info.host.adv_data,
                  &advertiseCmd.info.host.adv_data_len);
  
  /*设置16BIT 服务UUID 公有*/
  GAPM_AddAdvData(GAP_AD_TYPE_SERVICE_16_BIT_DATA, asha_uuid,
                  sizeof(asha_uuid), advertiseCmd.info.host.scan_rsp_data,
                  &advertiseCmd.info.host.scan_rsp_data_len);

  /* Set scan response data as company ID + ASHA UUID */
  advertiseCmd.info.host.scan_rsp_data_len = 0;
  
  /*设置厂家ID*/
  GAPM_AddAdvData(GAP_AD_TYPE_MANU_SPECIFIC_DATA, companyID,
                  APP_COMPANY_ID_LEN, advertiseCmd.info.host.adv_data,
                  &advertiseCmd.info.host.adv_data_len);
  
  /*设置16BIT 服务UUID 公有*/
  GAPM_AddAdvData(GAP_AD_TYPE_SERVICE_16_BIT_DATA, asha_uuid,
                  sizeof(asha_uuid), advertiseCmd.info.host.scan_rsp_data,
                  &advertiseCmd.info.host.scan_rsp_data_len);
}

/**
  ******************************************************************
  * @brief   设置通讯参数
  * @param   [in]conidx 任务ID
  * @param   [in]cfm 参数
  * @return  None.
  * @author  aron566
  * @version v1.0
  * @date    2021/8/24
  ******************************************************************
  */
static void APP_SetConnectionCfmParams(uint8_t conidx, struct gapc_connection_cfm* cfm)
{
    cfm->svc_changed_ind_enable = 0;
    cfm->ltk_present = false;
#ifdef SECURE_CONNECTION
        cfm->pairing_lvl = GAP_PAIRING_BOND_SECURE_CON;
#else
    cfm->pairing_lvl = GAP_PAIRING_BOND_UNAUTH;
#endif

#if CFG_BOND_LIST_IN_NVR2
    if(GAPC_IsBonded(conidx))
    {
        cfm->ltk_present = true;
        Device_Param_Read(PARAM_ID_CSRK, cfm->lcsrk.key);
        memcpy(cfm->rcsrk.key, GAPC_GetBondInfo(conidx)->CSRK, KEY_LEN);
        cfm->lsign_counter = 0xFFFFFFFF;
        cfm->rsign_counter = 0;
    }
#endif

    PRINTF("  connectionCfm->ltk_present = %d \n\r", cfm->ltk_present);
}

/* ----------------------------------------------------------------------------
 * Function      : Device_Param_Prepare(struct app_device_param * param)
 * ----------------------------------------------------------------------------
 * Description   : This function allows the application to overwrite a few BLE
 *                 parameters (BD address and keys) without having to write
 *                 data into RSL10 flash (NVR3). This function is called by the
 *                 stack and it's useful for debugging and testing purposes.
 * Inputs        : - param    - pointer to the parameters to be configured
 * Outputs       : None
 * Assumptions   : None
 * ------------------------------------------------------------------------- */
void Device_Param_Prepare(app_device_param_t *param)
{
    param->device_param_src_type = APP_BLE_DEV_PARAM_SOURCE;

    if(param->device_param_src_type == APP_PROVIDED)
    {
        uint8_t temp_bleAddress[6] = APP_BD_ADDRESS;

        memcpy(param->bleAddress, temp_bleAddress, 6);
    }
}


#include <app_audio.h>

extern const struct att_db_desc asha_att_db[];

extern audio_frame_param_t env_audio;

/* ----------------------------------------------------------------------------
 * Function      : void APP_ASHA_CallbackHandler(enum ASHA_Operation_t op, void *param)
 * ----------------------------------------------------------------------------
 * Description   : Application callback function to interact with ble_asha
 *                 service. Handle ASHA events to start/stop streaming or
 *                 change volume.
 * Inputs        : - op     - Kernel message ID number
 *                 - param  - Operation parameter to be type casted to:
 *                            - For op == ASHA_VOLUME_CHANGE,
 *                              param == struct asha_volume_change*
 *                            - For op == ASHA_AUDIO_START,
 *                              param == struct asha_audio_start*
 *                            - For op == ASHA_AUDIO_STOP,
 *                              param == NULL
 * Outputs       : None
 * Assumptions   : None
 * ------------------------------------------------------------------------- */
void APP_ASHA_CallbackHandler(enum ASHA_Operation_t op, void *param)
{
    switch(op)
    {
        case ASHA_VOLUME_CHANGE:
        {
            struct asha_volume_change* p = param;
            Volume_Set(p->volume);
            PRINTF("\r\nAPP_ASHA_CallbackHandler - ASHA_VOLUME_CHANGE: volume=%d\r\n", p->volume);
        }
        break;

        case ASHA_AUDIO_START:
        {
            struct asha_audio_start* p = param;
            Volume_Set(p->volume);
            APP_ResetPrevSeqNumber();
            PRINTF("\r\nAPP_ASHA_CallbackHandler - ASHA_AUDIO_START: codec=%d audiotype=%d volume=%d\r\n",
                    p->codec, p->audiotype, p->volume);

            if( env_audio.state == LINK_DISCONNECTED )
            {
                /* We don't directly start the rendering IRQs, we'll delay that
                 * to after we received an audio packet */
                env_audio.state = LINK_TRANSIENT;
            }
        }
        break;

        case ASHA_AUDIO_STOP:
        {
            PRINTF("\r\nAPP_ASHA_CallbackHandler - ASHA_AUDIO_STOP\r\n");

            APP_Audio_Disconnect();
        }
        break;

        case ASHA_AUDIO_RCVD:
        {
            struct asha_audio_received *rcv_p = (struct asha_audio_received *) param;
//            PRINTF("\r\nAPP_ASHA_CallbackHandler - ASHA_AUDIO_RCVD\r\n");
            APP_Audio_Transfer(rcv_p->data, rcv_p->length - 1, rcv_p->seq_number);
        }
        break;

        case ASHA_AUDIO_STATUS:
        {
            PRINTF("\r\nAPP_ASHA_CallbackHandler - ASHA_AUDIO_STATUS. Other peripheral state: %d\r\n", ((struct asha_audio_status *) param)->connected);
        }
        break;
    }
}

/* ----------------------------------------------------------------------------
 * Function      : void APP_GAPM_GATTM_Handler(ke_msg_id_t const msg_id,
 *                                     void const *param,
 *                                     ke_task_id_t const dest_id,
 *                                     ke_task_id_t const src_id)
 * ----------------------------------------------------------------------------
 * Description   : Handle GAPM/GATTM messages that need application action
 * Inputs        : - msg_id     - Kernel message ID number
 *                 - param      - Message parameter
 *                 - dest_id    - Destination task ID number
 *                 - src_id     - Source task ID number
 * Outputs       : None
 * Assumptions   : None
 * ------------------------------------------------------------------------- */
void APP_GAPM_GATTM_Handler(ke_msg_id_t const msg_id, void const *param,
                            ke_task_id_t const dest_id,
                            ke_task_id_t const src_id)
{
    switch(msg_id)
    {
        case GAPM_CMP_EVT:
        {
            const struct gapm_cmp_evt *p = param;
			/* Reset completed. Apply device configuration. */
            if(p->operation == GAPM_RESET)
            {
                GAPM_SetDevConfigCmd(&devConfigCmd);
                /* Trigger a GAPM_CMP_EVT / GAPM_SET_DEV_CONFIG when finished.
                 * BASS (ble_bass.c) and CUSTOMSS (app_customss.c) monitor this
                 * event before adding the profile/service to the stack. */
            }
            else if(p->operation == GAPM_SET_DEV_CONFIG && p->status == GAP_ERR_NO_ERROR)
            {
                /* Add custom services' attribute database (in this application only ASHA service) */
                GATTM_AddAttributeDatabase(asha_att_db, ASHA_MAX_IDX);
            }
            else if((p->operation == GAPM_RESOLV_ADDR) && /* IRK not found for address */
                    (p->status == GAP_ERR_NOT_FOUND))
            {
                struct gapc_connection_cfm cfm;
                uint8_t conidx = KE_IDX_GET(dest_id);
                APP_SetConnectionCfmParams(conidx, &cfm);
                GAPC_ConnectionCfm(conidx, &cfm); /* Confirm connection without LTK. */
                PRINTF("\r\nGAPM_CMP_EVT / GAPM_RESOLV_ADDR. conidx=%d Status = NOT FOUND", conidx);
            }
        }
        break;

        case GATTM_ADD_SVC_RSP:
        case GAPM_PROFILE_ADDED_IND:
        {
            /* If all expected profiles/services have been added */
            if(GAPM_GetProfileAddedCount() == APP_NUM_STD_PRF &&
               GATTM_GetServiceAddedCount() == APP_NUM_CUSTOM_SVC)
            {
                GAPM_StartAdvertiseCmd(&advertiseCmd); /* Start advertising */

                /* Start the LED periodic timer. LED blinks according to the
                 * number of connected peers. See APP_LED_Timeout_Handler. */
                ke_timer_set(APP_LED_TIMEOUT, TASK_APP, TIMER_SETTING_MS(200));
            }
        }
        break;

        case GAPM_ADDR_SOLVED_IND: /* Private address resolution was successful */
        {
            PRINTF("\r\nGAPM_ADDR_SOLVED_IND");
            struct gapc_connection_cfm cfm;
            uint8_t conidx = KE_IDX_GET(dest_id);
            APP_SetConnectionCfmParams(conidx, &cfm);
            GAPC_ConnectionCfm(conidx, &cfm); /* Send connection confirmation with LTK */
        }
        break;
    }
}

/* ----------------------------------------------------------------------------
 * Function      : void APP_GAPC_MsgHandler(ke_msg_id_t const msg_id,
 *                                     void const *param,
 *                                     ke_task_id_t const dest_id,
 *                                     ke_task_id_t const src_id)
 * ----------------------------------------------------------------------------
 * Description   : Handle GAPC messages that need application action
 * Inputs        : - msg_id     - Kernel message ID number
 *                 - param      - Message parameter
 *                 - dest_id    - Destination task ID number
 *                 - src_id     - Source task ID number
 * Outputs       : None
 * Assumptions   : None
 * ------------------------------------------------------------------------- */
void APP_GAPC_Handler(ke_msg_id_t const msg_id, void const *param,
                      ke_task_id_t const dest_id, ke_task_id_t const src_id)
{
    uint8_t conidx = KE_IDX_GET(src_id);

    switch(msg_id)
    {
        case GAPC_CONNECTION_REQ_IND:
        {
            const struct gapc_connection_req_ind* p = param;
            PRINTF("\r\nGAPC_CONNECTION_REQ_IND: con_interval=%d, con_latency = %d, sup_to = %d, clk_accuracy = %d",
                    p->con_interval,
                    p->con_latency,
                    p->sup_to,
                    p->clk_accuracy);
            PRINTF("\r\n  ADDR: ");
            for (uint8_t i = 0;i < GAP_BD_ADDR_LEN; i++)
                PRINTF("%d ", p->peer_addr.addr[i]);
            PRINTF("\r\n  ADDR_TYPE: %d", p->peer_addr_type);

#if CFG_BOND_LIST_IN_NVR2
            if(GAP_IsAddrPrivateResolvable(p->peer_addr.addr, p->peer_addr_type) &&
               BondList_Size() > 0)
            {
                PRINTF("\r\n    Starting GAPM_ResolvAddrCmd\r\n");
                GAPM_ResolvAddrCmd(conidx, p->peer_addr.addr, 0, NULL);
            }
            else
#endif
            {
                struct gapc_connection_cfm cfm;
                APP_SetConnectionCfmParams(conidx, &cfm);
                GAPC_ConnectionCfm(conidx, &cfm); /* Send connection confirmation */
            }

            /* If not yet connected to all peers, keep advertising */
            if((GAPC_GetConnectionCount() < APP_NB_PEERS))
            {
                GAPM_StartAdvertiseCmd(&advertiseCmd);
            }
        }
        break;

        case GAPC_DISCONNECT_IND:
        {
            GAPM_StartAdvertiseCmd(&advertiseCmd);
            APP_Audio_Disconnect();
            PRINTF("\r\nGAPC_DISCONNECT_IND: reason = %d", ((struct gapc_disconnect_ind*)param)->reason);
        }
        break;

        case GAPC_GET_DEV_INFO_REQ_IND:
        {
            const struct gapc_get_dev_info_req_ind* p = param;
            GAPC_GetDevInfoCfm(conidx, p->req, getDevInfoCfm[p->req]);
            PRINTF("\r\nGAPC_GET_DEV_INFO_REQ_IND: req = %d", p->req);
        }
        break;

        case GAPC_PARAM_UPDATE_REQ_IND:
        {
            GAPC_ParamUpdateCfm(conidx, true, 0xFFFF, 0xFFFF);

            PRINTF("\r\nGAPC_PARAM_UPDATE_REQ_IND: intv_min=%d, intv_max = %d, latency = %d, time_out = %d",
                   ((struct gapc_conn_param*) param)->intv_min,
                   ((struct gapc_conn_param*) param)->intv_max,
                   ((struct gapc_conn_param*) param)->latency,
                   ((struct gapc_conn_param*) param)->time_out);
        }
        break;

        case GAPC_PARAM_UPDATED_IND:
        {
            struct gapc_set_pref_slave_latency_cmd *cmd = KE_MSG_ALLOC(GAPC_SET_PREF_SLAVE_LATENCY_CMD,
                    KE_BUILD_ID(TASK_GAPC, conidx), TASK_APP, gapc_set_pref_slave_latency_cmd);

            cmd->operation = GAPC_SET_PREF_SLAVE_LATENCY;
            cmd->latency = 0;
            ke_msg_send(cmd);
        }
        break;

#if CFG_BOND_LIST_IN_NVR2
        case GAPC_ENCRYPT_REQ_IND:
        {
            const struct gapc_encrypt_req_ind* p = param;
            /* Accept request if bond information is valid & EDIV/RAND match */
            bool found = (GAPC_IsBonded(conidx) &&
                          p->ediv == GAPC_GetBondInfo(conidx)->EDIV &&
                          !memcmp(p->rand_nb.nb, GAPC_GetBondInfo(conidx)->RAND, GAP_RAND_NB_LEN));

            PRINTF("\r\nGAPC_ENCRYPT_REQ_IND: bond information %s", (found ? "FOUND" : "NOT FOUND"));
            PRINTF("\r\n    GAPC_isBonded=%d GAPC_EDIV=%d  GAPC_rand= %d %d %d %d   ",
                    GAPC_IsBonded(conidx), GAPC_GetBondInfo(conidx)->EDIV,
                    GAPC_GetBondInfo(conidx)->RAND[0], GAPC_GetBondInfo(conidx)->RAND[1],
                    GAPC_GetBondInfo(conidx)->RAND[2], GAPC_GetBondInfo(conidx)->RAND[3]);
            PRINTF("\r\n    p_EDIV=%d  p_rand= %d %d %d %d   ", p->ediv,
                   p->rand_nb.nb[0], p->rand_nb.nb[1], p->rand_nb.nb[2], p->rand_nb.nb[3]);

            GAPC_EncryptCfm(conidx, found, GAPC_GetBondInfo(conidx)->LTK);
        }
        break;

        case GAPC_ENCRYPT_IND:
        {
            PRINTF("\r\nGAPC_ENCRYPT_IND: Link encryption is ON");
        }
        break;

        case GAPC_BOND_REQ_IND:
        {
            const struct gapc_bond_req_ind* p = param;
            switch (p->request)
            {
                case GAPC_PAIRING_REQ:
                {
                    bool accept = BondList_Size() < APP_BONDLIST_SIZE;
                    union gapc_bond_cfm_data pairingRsp =
                    {
                        .pairing_feat =
                        {
                            .iocap = GAP_IO_CAP_NO_INPUT_NO_OUTPUT,
                            .oob = GAP_OOB_AUTH_DATA_NOT_PRESENT,
                            .key_size = KEY_LEN,
                            .ikey_dist = (GAP_KDIST_IDKEY | GAP_KDIST_SIGNKEY),
                            .rkey_dist = (GAP_KDIST_ENCKEY | GAP_KDIST_IDKEY | GAP_KDIST_SIGNKEY),
                        }
                    };
#ifdef SECURE_CONNECTION
                    if (p->data.auth_req & GAP_AUTH_SEC_CON)
                    {
                        pairingRsp.pairing_feat.auth = GAP_AUTH_REQ_SEC_CON_BOND;
                        pairingRsp.pairing_feat.sec_req = GAP_SEC1_SEC_CON_PAIR_ENC;
                    }
                    else
#endif    /* ifdef SECURE_CONNECTION */
                    {
                        pairingRsp.pairing_feat.auth = GAP_AUTH_REQ_NO_MITM_BOND;
                        pairingRsp.pairing_feat.sec_req = GAP_NO_SEC;
                    }
                    PRINTF("\r\nGAPC_BOND_REQ_IND / GAPC_PAIRING_REQ: accept = %d conidx=%d", accept, conidx);
                    GAPC_BondCfm(conidx, GAPC_PAIRING_RSP, accept, &pairingRsp);
                }
                break;

                case GAPC_LTK_EXCH: /* Prepare and send random LTK (legacy only) */
                {
                    PRINTF("\r\nGAPC_BOND_REQ_IND / GAPC_LTK_EXCH");
                    union gapc_bond_cfm_data ltkExch;
                    ltkExch.ltk.ediv = co_rand_hword();
                    for(uint8_t i = 0, i2 = GAP_RAND_NB_LEN; i < GAP_RAND_NB_LEN; i++, i2++)
                    {
                        ltkExch.ltk.randnb.nb[i] = co_rand_byte();
                        ltkExch.ltk.ltk.key[i] = co_rand_byte();
                        ltkExch.ltk.ltk.key[i2] = co_rand_byte();
                    }
                    GAPC_BondCfm(conidx, GAPC_LTK_EXCH, true, &ltkExch); /* Send confirmation */
                }
                break;

                case GAPC_TK_EXCH: /* Prepare and send TK */
                {
                    PRINTF("\r\nGAPC_BOND_REQ_IND / GAPC_TK_EXCH");
                    /* IO Capabilities are set to GAP_IO_CAP_NO_INPUT_NO_OUTPUT in this application.
                     * Therefore TK exchange is NOT performed. It is always set to 0 (Just Works algorithm). */
                }
                break;

                case GAPC_IRK_EXCH:
                {
                    PRINTF("\r\nGAPC_BOND_REQ_IND / GAPC_IRK_EXCH");
                    union gapc_bond_cfm_data irkExch;
                    memcpy(irkExch.irk.addr.addr.addr, GAPM_GetDeviceConfig()->addr.addr, GAP_BD_ADDR_LEN);
                    irkExch.irk.addr.addr_type = GAPM_GetDeviceConfig()->addr_type;
                    memcpy(irkExch.irk.irk.key, GAPM_GetDeviceConfig()->irk.key, GAP_KEY_LEN);
                    GAPC_BondCfm(conidx, GAPC_IRK_EXCH, true, &irkExch); /* Send confirmation */
                }
                break;

                case GAPC_CSRK_EXCH:
                {
                    PRINTF("\r\nGAPC_BOND_REQ_IND / GAPC_CSRK_EXCH");
                    union gapc_bond_cfm_data csrkExch;
                    Device_Param_Read(PARAM_ID_CSRK, csrkExch.csrk.key);
                    GAPC_BondCfm(conidx, GAPC_CSRK_EXCH, true, &csrkExch); /* Send confirmation */
                }
                break;
            }
        }
        break;
#endif /* CFG_BOND_LIST_IN_NVR2 */
    }
}

/* ----------------------------------------------------------------------------
 * Function      : void APP_LED_Timeout_Handler(ke_msg_idd_t const msg_id,
 *                                              void const *param,
 *                                              ke_task_id_t const dest_id,
 *                                              ke_task_id_t const src_id)
 * ----------------------------------------------------------------------------
 * Description   : Control GPIO "LED_DIO_NUM" behavior using a timer.
 *                 Possible LED behaviors:
 *                     - If the device is advertising but it has not connected
 *                       to any peer: the LED blinks every 200 ms.
 *                     - If the device is advertising and it is connecting to
 *                       fewer than BLE_CONNECTION_MAX peers: the LED blinks
 *                       every 2 seconds according to the number of connected
 *                       peers (i.e., blinks once if one peer is connected,
 *                       twice if two peers are connected, etc.).
 *                     - If the device is connected to BLE_CONNECTION_MAX peers
 *                       the LED is steady on.
 * Inputs        : - msg_id     - Kernel message ID number
 *                 - param      - Message parameter (unused)
 *                 - dest_id    - Destination task ID number
 *                 - src_id     - Source task ID number
 * Outputs       : None
 * Assumptions   : None
 * ------------------------------------------------------------------------- */
void APP_LED_Timeout_Handler(ke_msg_id_t const msg_id, void const *param,
                             ke_task_id_t const dest_id, ke_task_id_t const src_id)
{
    static uint8_t toggle_cnt = 0;
    uint8_t connectionCount = GAPC_GetConnectionCount();

    /* Blink LED according to the number of connections */
    switch (connectionCount)
    {
        case 0:
        {
            ke_timer_set(APP_LED_TIMEOUT, TASK_APP, TIMER_SETTING_MS(200));
            Sys_GPIO_Toggle(LED_DIO_NUM); /* Toggle LED_DIO_NUM every 200ms */
            toggle_cnt = 0;
        }
        break;

        case APP_NB_PEERS:
        {
            ke_timer_set(APP_LED_TIMEOUT, TASK_APP, TIMER_SETTING_MS(200));
            Sys_GPIO_Set_High(LED_DIO_NUM); /* LED_DIO_NUM steady high */
            toggle_cnt = 0;
        }
        break;

        default: /* connectionCount is between 1 and APP_NB_PEERS (exclusive) */
        {
            if (toggle_cnt >= connectionCount * 2)
            {
                toggle_cnt = 0;
                ke_timer_set(APP_LED_TIMEOUT, TASK_APP, TIMER_SETTING_S(2)); /* Schedule timer for a long 2s break */
                Sys_GPIO_Set_High(LED_DIO_NUM); /* LED_DIO_NUM steady high until next 2s blinking period */
            }
            else
            {
                toggle_cnt++;
                Sys_GPIO_Toggle(LED_DIO_NUM);
                ke_timer_set(APP_LED_TIMEOUT, TASK_APP, TIMER_SETTING_MS(200));
            }
        }
    }
}

/** Public application code --------------------------------------------------*/
/*******************************************************************************
*
*       Public code
*
********************************************************************************
*/
/**
  ******************************************************************
  * @brief   清空绑定列表
  * @param   [in]None.
  * @return  true 成功.
  * @author  aron566
  * @version v1.0
  * @date    2021/8/24
  ******************************************************************
  */
bool BLE_Port_BondList_RemoveAll(void)
{
  /* Run the following command when erasing flash/bond_list is desirable */
  return BondList_RemoveAll();  
}

/**
  ******************************************************************
  * @brief   蓝牙协议栈启动
  * @param   [in]None.
  * @return  None.
  * @author  aron566
  * @version v1.0
  * @date    2021/8/13
  ******************************************************************
  */
void BLE_Port_Start(void)
{ 
  /*执行事件调度*/
  Kernel_Schedule();
}

/**
  ******************************************************************
  * @brief   蓝牙初始化
  * @param   [in]None.
  * @return  None.
  * @author  aron566
  * @version v1.0
  * @date    2021/8/5
  ******************************************************************
  */
void BLE_Port_Init(void)
{
  /*蓝牙时钟初始化*/
  BLE_Port_Clock_Init();
  
  /*初始化音频蓝牙 */
  Audio_Initialize_System();

  /* Enable Flash overlay */
  memcpy((uint8_t *)PRAM0_BASE, (uint8_t *)FLASH_MAIN_BASE, PRAM0_SIZE);
  memcpy((uint8_t *)PRAM1_BASE, (uint8_t *)(FLASH_MAIN_BASE + PRAM0_SIZE),
        PRAM1_SIZE);
  memcpy((uint8_t *)PRAM2_BASE, (uint8_t *)(FLASH_MAIN_BASE + PRAM0_SIZE +
                                           PRAM1_SIZE), PRAM2_SIZE);
  memcpy((uint8_t *)PRAM3_BASE, (uint8_t *)(FLASH_MAIN_BASE + PRAM0_SIZE +
                                           PRAM1_SIZE + PRAM2_SIZE),
        PRAM3_SIZE);
  SYSCTRL->FLASH_OVERLAY_CFG = 0xf;

  /* Enable CM3 loop cache */
  SYSCTRL->CSS_LOOP_CACHE_CFG = CSS_LOOP_CACHE_ENABLE;
    
  /* Configure application-specific advertising data and scan response  data*/
  APP_SetAdvScanData();
  
  /*配置服务*/
  /* Configure Battery Service Server */
  BASS_Setup();

  /* Configure Device Information Service Server */
  DISS_Setup();
    
  /* Initialize Android Audio Streaming Hearing Aid service */
  ASHA_Initialize(&ashaReadOnlyProperties, APP_ASHA_CallbackHandler);

  /* Add application message handlers */
  MsgHandler_Add(TASK_ID_GAPM, APP_GAPM_GATTM_Handler);
  MsgHandler_Add(GATTM_ADD_SVC_RSP, APP_GAPM_GATTM_Handler);
  MsgHandler_Add(TASK_ID_GAPC, APP_GAPC_Handler);
  MsgHandler_Add(APP_LED_TIMEOUT, APP_LED_Timeout_Handler);
  MsgHandler_Add(APP_BATT_LEVEL_LOW, APP_BASS_BattLevelLow_Handler);
    
  /* Reset the GAP manager. Trigger GAPM_CMP_EVT / GAPM_RESET when finished.
   * See SCAN_MsgHandler */
  GAPM_ResetCmd();   
}

#ifdef __cplusplus ///<end extern c
}
#endif
/******************************** End of file *********************************/

/**
 *  @file BLE_Port.h
 *
 *  @date 2021/8/5
 *
 *  @author aron566.
 *
 *  @brief 蓝牙驱动
 *  
 *  @version v1.0
 */
#ifndef BLE_PORT_H
#define BLE_PORT_H
#ifdef __cplusplus ///<use C compiler
extern "C" {
#endif
/** Includes -----------------------------------------------------------------*/
#include <stdint.h> /*need definition of uint8_t*/
#include <stddef.h> /*need definition of NULL*/
#include <stdbool.h>/*need definition of BOOL*/
#include <stdio.h>  /*if need printf*/
#include <stdlib.h>
#include <string.h>
#include <limits.h> /**< if need INT_MAX*/
/** Private includes ---------------------------------------------------------*/
#include <rwip_task.h>  
/** Private defines ----------------------------------------------------------*/

/** Exported typedefines -----------------------------------------------------*/
/* APP Task messages */
enum appm_msg
{
    APPM_DUMMY_MSG = TASK_FIRST_MSG(TASK_ID_APP),
    APP_LED_TIMEOUT,
    APP_BATT_LEVEL_LOW
};
/** Exported constants -------------------------------------------------------*/
/** Exported macros-----------------------------------------------------------*/
#define LED_DIO_NUM                     6  /* DIO number that is connected to LED of EVB */

/* Timer setting in units of 10ms (kernel timer resolution) */
#define TIMER_SETTING_MS(MS)            (MS / 10)
#define TIMER_SETTING_S(S)              (S * 100)
/** Exported variables -------------------------------------------------------*/
/** Exported functions prototypes --------------------------------------------*/

/*蓝牙初始化*/  
void BLE_Port_Init(void);
/*蓝牙接口启动*/  
void BLE_Port_Start(void);
/*清空绑定列表*/
bool BLE_Port_BondList_RemoveAll(void);

#ifdef __cplusplus ///<end extern c
}
#endif
#endif
/******************************** End of file *********************************/

3、调用

int main(void)
{
	/*时钟初始化*/
	...
  	/*蓝牙接口初始化*/
  	BLE_Port_Init();
  	
	while(1)
	{
	    /*启动蓝牙*/
    	BLE_Port_Start();
    }
}

BLE Slave

BLE Master

BLE Audio Stream

基于RSL10的Bootloader

官方给了一个BL工程,我这边暂时没有使用,而是沿用之前编写的BL工程框架移植到RSL10中去,完美运行。代码约占用50KB(未开优化),官方8KB,所以功能方面差异较大。

BL工程参考

特别需要注意的地方

调试相关

调试状态下,可以不设定看门狗和喂狗
退出调试一定开看门狗,否则设备不断重启,也就是看门狗无法关闭

功耗相关

int main(void)
{

	while(1)
	{
		...
	  	/* Wait for an event before executing the scheduler again. */
  		SYS_WAIT_FOR_EVENT;
	}
}

电源
为了能够使用最小1.1 V的VBAT,应遵守以下降低的操作条件:

  • 最大Tx功率0 dBm。
  • SYSCLK≤24mhz。
  • 功能温度范围限制在0−50℃

应采用以下微调参数:

  • VCC = 1.10 v
  • VDDC = 0.92 v
  • VDDM = 1.05 V,将在电池寿命结束时受到VCC的限制
  • VDDRF = 1.05 V,将在电池寿命结束时受到VCC的限制。

VDDPA应该关闭
当VCC低于1.03 V时,RSL10应进入end - of - battery - life工作模式。如果限制VBAT≥1.10 V, VCC将保持在1.03 V以上

DSP核开发

前往

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

aron566

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值