sdk-hwV1.3/lichee/xr806/appos/project/example/adc/main.c

260 lines
6.5 KiB
C
Executable File

/*
* Copyright (C) 2017 XRADIO TECHNOLOGY CO., LTD. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
* 3. Neither the name of XRADIO TECHNOLOGY CO., LTD. nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include "kernel/os/os.h"
#include "driver/chip/hal_adc.h"
#include "driver/chip/private/hal_os.h"
#include "common/framework/platform_init.h"
#define ADC_BURST_MODE (0)
#define ADC_IRQ_MODE ADC_IRQ_DATA
#define ADC_CHL ADC_CHANNEL_VBAT
#define ADC_FEQ 100000
#define ADC_FIRST_DELAY 10
HAL_Semaphore voltage_sem;
#define ADC_VOL_SEM_INIT() HAL_SemaphoreInitBinary(&voltage_sem)
#define ADC_VOL_SEM_WAIT() HAL_SemaphoreWait(&voltage_sem, HAL_WAIT_FOREVER)
#define ADC_VOL_SEM_RELEASE() HAL_SemaphoreRelease(&voltage_sem)
#define ADC_VOL_SEM_DEINIT() HAL_SemaphoreDeinit(&voltage_sem)
static uint8_t adc_value_status = 1;
static uint32_t adc_data[10];
static void adc_callback(void *arg)
{
ADC_Channel chl = *((ADC_Channel *)arg);
if (adc_value_status) {
#if ADC_BURST_MODE
HAL_ADC_FifoConfigChannel(chl, ADC_SELECT_DISABLE);
#else
HAL_ADC_ConfigChannel(chl, ADC_SELECT_DISABLE, ADC_IRQ_MODE, 0, 0);
#endif
return;
}
static uint32_t count = 0;
#if ADC_BURST_MODE
for (count = 0; count < 10; count++)
adc_data[count] = HAL_ADC_GetFifoData();
HAL_ADC_FifoConfigChannel(chl, ADC_SELECT_DISABLE);
adc_value_status = 1;
ADC_VOL_SEM_RELEASE();
#else
if (HAL_ADC_GetIRQState(chl) == ADC_DATA_IRQ) {
if (count >= 10) {
count = 0;
HAL_ADC_ConfigChannel(chl, ADC_SELECT_DISABLE, ADC_IRQ_MODE, 0, 0);
adc_value_status = 1;
ADC_VOL_SEM_RELEASE();
} else
adc_data[count++] = HAL_ADC_GetValue(chl);
}
#endif
}
static void adc_init(void)
{
HAL_Status status = HAL_ERROR;
ADC_InitParam initParam;
#if (CONFIG_CHIP_ARCH_VER == 3)
initParam.work_clk = ADC_WORKCLK_HFCLK;
#endif
initParam.delay = ADC_FIRST_DELAY;
initParam.freq = ADC_FEQ;
#if (CONFIG_CHIP_ARCH_VER > 1)
initParam.vref_mode = ADC_VREF_MODE_1;
#endif
#if ADC_BURST_MODE
initParam.mode = ADC_BURST_CONV;
#else
initParam.mode = ADC_CONTI_CONV;
#endif
printf("ADC init...\n");
status = HAL_ADC_Init(&initParam);
if (status != HAL_OK) {
printf("ADC init error %d\n", status);
return;
}
}
static void adc_deinit(void)
{
HAL_Status status = HAL_ERROR;
status = HAL_ADC_DeInit();
if (status != HAL_OK)
printf("ADC deinit error %d\n", status);
}
static uint32_t adc_filter(uint32_t adc_data[10])
{
uint8_t j = 0, i = 0;
uint32_t sum = 0;
uint32_t max = 0;
for (i = 0; i < 10; i++) {
for (j = i; j < 9; j++) {
if (adc_data[i] >= adc_data[j+1]) {
max = adc_data[i];
adc_data[i] = adc_data[j+1];
adc_data[j+1] = max;
}
}
}
for (i = 0; i < 10; i++) {
sum = sum + adc_data[i];
}
sum = (sum - adc_data[0] - adc_data[9]) / 8;
return sum;
}
static void adc_voltage_init(void)
{
ADC_VOL_SEM_INIT();
adc_init();
}
static void adc_voltage_config(uint8_t channel, uint8_t en)
{
HAL_Status status = HAL_ERROR;
ADC_Channel chl = (ADC_Channel)channel;
if (en) {
printf("ADC channel config...\n");
#if ADC_BURST_MODE
status = HAL_ADC_FifoConfigChannel(chl, ADC_SELECT_ENABLE);
#else
status = HAL_ADC_ConfigChannel(chl, ADC_SELECT_ENABLE, ADC_IRQ_MODE, 0, 0);
#endif
if (status != HAL_OK) {
printf("ADC config error %d\n", status);
return;
}
printf("ADC callback enable...\n");
status = HAL_ADC_EnableIRQCallback(chl, adc_callback, &chl);
if (status != HAL_OK) {
printf("ADC IRQ Enable error %d\n", status);
return;
}
printf("ADC convert start...\n");
status = HAL_ADC_Start_Conv_IT();
if (status != HAL_OK) {
printf("ADC it mode start error %d\n", status);
return;
}
} else {
printf("ADC convert stop...\n");
HAL_ADC_Stop_Conv_IT();
printf("ADC callback disable...\n");
HAL_ADC_DisableIRQCallback(chl);
}
}
/*
* The relationship between adc value and voltage conversion is as follows:
* voltage = adc_value * 2500 * ratio / 4096(mv), ratio=1 when adc channel is chl0~chl6,
* ratio=3 when adc channel is chl8,
*/
static uint32_t adc_voltage_get(uint8_t channel)
{
HAL_Status status = HAL_ERROR;
adc_value_status = 0;
ADC_Channel chl = (ADC_Channel)channel;
uint8_t ratio = (chl == ADC_CHANNEL_VBAT) ? 3 : 1;
#if ADC_BURST_MODE
status = HAL_ADC_FifoConfigChannel(chl, ADC_SELECT_ENABLE);
#else
status = HAL_ADC_ConfigChannel(chl, ADC_SELECT_ENABLE, ADC_IRQ_MODE, 0, 0);
#endif
if (status != HAL_OK) {
printf("ADC it mode start error %d\n", status);
}
ADC_VOL_SEM_WAIT();
if (adc_value_status) {
uint32_t adc_value = adc_filter(adc_data);
return (adc_value * 2500 * ratio / 4096);
}
return 0;
}
static void adc_voltage_deinit(void)
{
adc_deinit();
ADC_VOL_SEM_DEINIT();
}
int main(void)
{
platform_init();
printf("ADC demo started.\n");
OS_MSleep(500);
adc_voltage_init();
adc_voltage_config(ADC_CHL, 1);
printf("ADC get channel voltage...\n");
uint32_t voltage;
while (1) {
voltage = adc_voltage_get(ADC_CHL);
if (voltage)
printf("VBAT voltage: %dmV\n", voltage);
OS_MSleep(1000);
}
adc_voltage_config(ADC_CHL, 0);
adc_voltage_deinit();
printf("ADC demo over.\n");
return 0;
}