芯科BG22学习笔记:9-如何添加ADC(寄存器+图像化)
实验目的:BG22芯片添加ADC功能
实验环境:Simplicity Studio V5
实验器材:Wireless Starter Kit Mainboard (BRD4002A Rev B06) + EFR32xG22 2.4 GHz 6 dBm QFN40 Radio Board (BRD4182A)
实验开始:
1. 新建工程,蓝牙工程输入soc empty, 普通MCU工程输入empty c


2. 添加组件:串口组件/LOG组件/浮点打印组件 (生成工程时系统已安装IADC组件,所以无需添加IADC组件)



3. app.c 替换成如下
#include "em_common.h"
#include "app_assert.h"
#include "sl_bluetooth.h"
#include "app.h"
#include "em_cmu.h"
#include "em_iadc.h"
#include "app_log.h"
// The advertising set handle allocated from Bluetooth stack.
static uint8_t advertising_set_handle = 0xff;
// Set CLK_ADC to 10MHz
#define CLK_SRC_ADC_FREQ 20000000 // CLK_SRC_ADC
#define CLK_ADC_FREQ 10000000 // CLK_ADC - 10 MHz max in normal mode
// Number of scan channels
#define NUM_INPUTS 8
/*
* Specify the IADC input using the IADC_PosInput_t typedef. This
* must be paired with a corresponding macro definition that allocates
* the corresponding ABUS to the IADC. These are...
*
* GPIO->ABUSALLOC |= GPIO_ABUSALLOC_AEVEN0_ADC0
* GPIO->ABUSALLOC |= GPIO_ABUSALLOC_AODD0_ADC0
* GPIO->BBUSALLOC |= GPIO_BBUSALLOC_BEVEN0_ADC0
* GPIO->BBUSALLOC |= GPIO_BBUSALLOC_BODD0_ADC0
* GPIO->CDBUSALLOC |= GPIO_CDBUSALLOC_CDEVEN0_ADC0
* GPIO->CDBUSALLOC |= GPIO_CDBUSALLOC_CDODD0_ADC0
*
* ...for port A, port B, and port C/D pins, even and odd, respectively.
*/
#define IADC_INPUT_0_PORT_PIN iadcPosInputPortBPin0;
#define IADC_INPUT_1_PORT_PIN iadcPosInputPortBPin1;
#define IADC_INPUT_0_BUS BBUSALLOC //PB0是B BUS
#define IADC_INPUT_0_BUSALLOC GPIO_BBUSALLOC_BEVEN0_ADC0 //PB0是B BUS的偶数管脚
#define IADC_INPUT_1_BUS BBUSALLOC //PB1是B BUS
#define IADC_INPUT_1_BUSALLOC GPIO_BBUSALLOC_BODD0_ADC0 //PB1是B BUS的奇数管脚
/*
* This example enters EM2 in the main while() loop; Setting this #define
* to 1 enables debug connectivity in EM2, which increases current
* consumption by about 0.5 uA.
*/
#define EM2DEBUG 1
/*******************************************************************************
*************************** GLOBAL VARIABLES ******************************
******************************************************************************/
static volatile double scanResult[NUM_INPUTS]; // Volts
//#define IADC0_FIFOENTRIES 0x8UL in em_iadc.c
void initIADC (void)
{
// Declare init structs
IADC_Init_t init = IADC_INIT_DEFAULT;
IADC_AllConfigs_t initAllConfigs = IADC_ALLCONFIGS_DEFAULT;
IADC_InitScan_t initScan = IADC_INITSCAN_DEFAULT;
IADC_ScanTable_t initScanTable = IADC_SCANTABLE_DEFAULT; // Scan Table
/*
* Enable IADC0 and GPIO clock branches.
*
* Note: On EFR32xG21 devices, CMU_ClockEnable() calls have no effect
* as clocks are enabled/disabled on-demand in response to peripheral
* requests. Deleting such lines is safe on xG21 devices and will
* reduce provide a small reduction in code size.
*/
CMU_ClockEnable(cmuClock_IADC0, true);
CMU_ClockEnable(cmuClock_GPIO, true);
// Select clock for IADC
CMU_ClockSelectSet(cmuClock_IADCCLK, cmuSelect_FSRCO);
// Modify init structures and initialize
init.warmup = iadcWarmupKeepWarm;
// Set the HFSCLK prescale value here
init.srcClkPrescale = IADC_calcSrcClkPrescale(IADC0, CLK_SRC_ADC_FREQ, 0);
/*
* Configuration 0 is used by both scan and single conversions by
* default. Use internal bandgap as the reference and specify the
* reference voltage in mV.
*
* Resolution is not configurable directly but is based on the
* selected oversampling ratio (osrHighSpeed), which defaults to
* 2x and generates 12-bit results.
*/
initAllConfigs.configs[0].reference = iadcCfgReferenceInt1V2;
initAllConfigs.configs[0].vRef = 1210;
initAllConfigs.configs[0].osrHighSpeed = iadcCfgOsrHighSpeed2x;
initAllConfigs.configs[0].analogGain = iadcCfgAnalogGain0P5x;
// Divide CLK_SRC_ADC to set the CLK_ADC frequency
initAllConfigs.configs[0].adcClkPrescale = IADC_calcAdcClkPrescale(IADC0,
CLK_ADC_FREQ,
0,
iadcCfgModeNormal,
init.srcClkPrescale);
/*
* Set the SCANFIFODVL flag when there are 4 entries in the scan
* FIFO. Note that in this example, the interrupt associated with
* the SCANFIFODVL flag in the IADC_IF register is not used.
*
* Similarly, the fifoDmaWakeup member of the initScan structure
* is left at its default setting of false, so LDMA service is not
* requested when the FIFO holds the specified number of samples.
*/
initScan.dataValidLevel = _IADC_SCANFIFOCFG_DVL_VALID4;
// Tag FIFO entry with scan table entry id.
initScan.showId = true;
/*
* Configure entries in scan table. CH0 is single-ended from
* input 0; CH1 is single-ended from input 1.
*/
initScanTable.entries[0].posInput = IADC_INPUT_0_PORT_PIN;
initScanTable.entries[0].negInput = iadcNegInputGnd;
initScanTable.entries[0].includeInScan = true;
initScanTable.entries[1].posInput = IADC_INPUT_1_PORT_PIN;
initScanTable.entries[1].negInput = iadcNegInputGnd;
initScanTable.entries[1].includeInScan = true;
initScanTable.entries[2].posInput = iadcPosInputAvdd; // Add AVDD to scan for demonstration purposes
initScanTable.entries[2].negInput = iadcNegInputGnd | 1; // When measuring a supply, PINNEG must be odd (1, 3, 5,...)
initScanTable.entries[2].includeInScan = true;
initScanTable.entries[3].posInput = iadcPosInputVddio; // Add VDDIO to scan for demonstration purposes
initScanTable.entries[3].negInput = iadcNegInputGnd | 1; // When measuring a supply, PINNEG must be odd (1, 3, 5,...)
initScanTable.entries[3].includeInScan = true;
initScanTable.entries[4].posInput = iadcPosInputVss; // Add VSS to scan for demonstration purposes
initScanTable.entries[4].negInput = iadcNegInputGnd | 1; // When measuring a supply, PINNEG must be odd (1, 3, 5,...)
initScanTable.entries[4].includeInScan = false; // FIFO is only 4 entries deep
initScanTable.entries[5].posInput = iadcPosInputVssaux; // Add VSSAUX (same as VSS) to scan for demonstration purposes
initScanTable.entries[5].negInput = iadcNegInputGnd | 1; // When measuring a supply, PINNEG must be odd (1, 3, 5,...)
initScanTable.entries[5].includeInScan = false;
initScanTable.entries[6].posInput = iadcPosInputDvdd; // Add DVDD to scan for demonstration purposes
initScanTable.entries[6].negInput = iadcNegInputGnd | 1; // When measuring a supply, PINNEG must be odd (1, 3, 5,...)
initScanTable.entries[6].includeInScan = false;
initScanTable.entries[7].posInput = iadcPosInputDecouple; // Add DECOUPLE to scan for demonstration purposes
initScanTable.entries[7].negInput = iadcNegInputGnd | 1; // When measuring a supply, PINNEG must be odd (1, 3, 5,...)
initScanTable.entries[7].includeInScan = false;
// Initialize IADC
IADC_init(IADC0, &init, &initAllConfigs);
// Initialize scan
IADC_initScan(IADC0, &initScan, &initScanTable);
// Allocate the analog bus for ADC0 inputs 对应GPIO管脚设置为模拟输入
GPIO->IADC_INPUT_0_BUS |= IADC_INPUT_0_BUSALLOC;
GPIO->IADC_INPUT_1_BUS |= IADC_INPUT_1_BUSALLOC;
// Clear any previous interrupt flags
IADC_clearInt(IADC0, _IADC_IF_MASK);
// Enable Scan interrupts
IADC_enableInt(IADC0, IADC_IEN_SCANTABLEDONE);
// Enable ADC interrupts
NVIC_ClearPendingIRQ(IADC_IRQn);
NVIC_EnableIRQ(IADC_IRQn);
}
/**************************************************************************//**
* @brief IADC interrupt handler
*****************************************************************************/
void IADC_IRQHandler(void)
{
IADC_Result_t result = {0, 0};
app_log_info("ADC IRQ Happened.\n");
// While the FIFO count is non-zero...
while (IADC_getScanFifoCnt(IADC0))
{
// Pull a scan result from the FIFO
result = IADC_pullScanFifoResult(IADC0);
/*
* Calculate the voltage converted as follows:
*
* For single-ended conversions, the result can range from 0 to
* +Vref, i.e., for Vref = VBGR = 1.21V, and with analog gain = 0.5
* 0xFFF represents the full scale value of 2.42V.
*/
scanResult[result.id] = result.data * 2.42 / 0xFFF;
// sl_app_log("ScanResult:%.2f\r\n", scanResult[result.id]);//打印输出数值
/*
* Scan results 2 - 6 are for external supply voltages, which are
* presented to the IADC divided by 4 for conversion. Back this
* out to get the correct result in volts. Note that DECOUPLE,
* scan table entry 7 in this example, is an internal supply (the
* output of the core supply regulator) and is connected directly
* to the IADC without a divide-by-4 stage.
*/
if ((result.id > 1) && (result.id < 7))
{
scanResult[result.id] *= 4;
}
// app_log_info("scanID: 0x%02x\n", result.id);
app_log_info("scanID: 0x%02x,scanResult: %.2fV\n", result.id, scanResult[result.id]);
}
// Alternate between the first and second set of scan table entries.
// if (result.id == 3) {
// IADC_setScanMask(IADC0, 0x00F0);
// }
// else {
// IADC_setScanMask(IADC0, 0x000F);
// }
/*
* Clear the scan table complete interrupt. Reading FIFO results
* does not do this automatically.
*/
IADC_clearInt(IADC0, IADC_IF_SCANTABLEDONE);
}
/**************************************************************************//**
* Application Init.
*****************************************************************************/
SL_WEAK void app_init(void)
{
/////////////////////////////////////////////////////////////////////////////
// Put your additional application init code here! //
// This is called once during start-up. //
/////////////////////////////////////////////////////////////////////////////
app_log_init();
initIADC();
app_log_info("ADC initialed.\n");
#ifdef EM2DEBUG
#if (EM2DEBUG == 1)
// Enable debug connectivity in EM2
EMU->CTRL_SET = EMU_CTRL_EM2DBGEN;
#endif
#endif
}
/**************************************************************************//**
* Application Process Action.
*****************************************************************************/
SL_WEAK void app_process_action(void)
{
/////////////////////////////////////////////////////////////////////////////
// Put your additional application code here! //
// This is called infinitely. //
// Do not call blocking functions from here! //
/////////////////////////////////////////////////////////////////////////////
//sl_app_log("START IADC.\r\n");
}
/**************************************************************************//**
* Bluetooth stack event handler.
* This overrides the dummy weak implementation.
*
* @param[in] evt Event coming from the Bluetooth stack.
*****************************************************************************/
void sl_bt_on_event(sl_bt_msg_t *evt)
{
sl_status_t sc;
switch (SL_BT_MSG_ID(evt->header)) {
// -------------------------------
// This event indicates the device has started and the radio is ready.
// Do not call any stack command before receiving this boot event!
case sl_bt_evt_system_boot_id:
// Create an advertising set.
sc = sl_bt_advertiser_create_set(&advertising_set_handle);
app_assert_status(sc);
// Generate data for advertising
sc = sl_bt_legacy_advertiser_generate_data(advertising_set_handle,
sl_bt_advertiser_general_discoverable);
app_assert_status(sc);
// Set advertising interval to 100ms.
sc = sl_bt_advertiser_set_timing(
advertising_set_handle,
160, // min. adv. interval (milliseconds * 1.6)
160, // max. adv. interval (milliseconds * 1.6)
0, // adv. duration
0); // max. num. adv. events
app_assert_status(sc);
// Start advertising and enable connections.
sc = sl_bt_legacy_advertiser_start(advertising_set_handle,
sl_bt_legacy_advertiser_connectable);
app_assert_status(sc);
break;
// -------------------------------
// This event indicates that a new connection was opened.
case sl_bt_evt_connection_opened_id:
IADC_command(IADC0, iadcCmdStartScan);
IADC_setScanMask(IADC0, 0x00FF);
break;
// -------------------------------
// This event indicates that a connection was closed.
case sl_bt_evt_connection_closed_id:
// Generate data for advertising
sc = sl_bt_legacy_advertiser_generate_data(advertising_set_handle,
sl_bt_advertiser_general_discoverable);
app_assert_status(sc);
// Restart advertising after client has disconnected.
sc = sl_bt_legacy_advertiser_start(advertising_set_handle,
sl_bt_legacy_advertiser_connectable);
app_assert_status(sc);
break;
///////////////////////////////////////////////////////////////////////////
// Add additional event handlers here as your application requires! //
///////////////////////////////////////////////////////////////////////////
// -------------------------------
// Default event handler.
default:
break;
}
}
4. 该程序每次连蓝牙成功后触发一次ADC转换;转换完成后进一次中断,从FIFO中读出4个数据(FIFO深度为4);其中前两个数据为PB00和PB01的电压值;
完

浙公网安备 33010602011771号