|
关于 MK64 MQX BSP(板级支持包)ADC USART等最最底层的驱动的疑问
最近,新的项目接触飞思卡尔的K64 和 MQX,在ADC\USART等硬件驱动,存在迷惑!
最最底层的硬件初始化(比如I/O口功能的选择、跟据AD通道配置相应的IO功能)我找不到在哪里配置的?
比如,以下为BSP的 initBSP.c(硬件初始化文件),以ADC0为例:
如果我使能ADC0模块 #define BSPCFG_ENABLE_ADC0 1
initbsp就会执行以下的ADC0初始化函数:_io_adc_install("adc0:", (void *) &_bsp_adc0_init);
#if BSPCFG_ENABLE_ADC0
_io_adc_install("adc0:", (void *) &_bsp_adc0_init);
#endif
分析ADC0的 初始化函数_io_adc_install主要是依据 &_bsp_adc0_init的内容:
内容包括给ADC0S模块分配时钟源、设置时间分频、AD采样速率、中断向量、中断优先级以及ADC0的触发方式等。
typedef struct kadc_install_struct
{
/* The number of ADC peripheral, use adc_t enum from PSP */
uint8_t ADC_NUMBER;
/* The clock source */
ADC_CLOCK_SOURCE CLOCK_SOURCE;
/* The clock divisor for ADC */
ADC_CLOCK_DIV CLOCK_DIV;
/* ADC high speed control, see ADC_HSC enum */
ADC_HSC SPEED;
/* ADC low power control, see ADC_LPC enum */
ADC_LPC POWER;
/* The calibration data pointer */
uint8_t *CALIBRATION_DATA_PTR;
/* ADC interrupt vector */
uint32_t ADC_VECTOR;
/* ADC interrupt vector */
uint32_t ADC_PRIORITY;
/* KPDB init structure */
const KPDB_INIT_STRUCT * PDB_INIT;
} KADC_INIT_STRUCT, * KADC_INIT_STRUCT_PTR;
/////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
const KADC_INIT_STRUCT _bsp_adc0_init = {
/* The number of ADC peripheral, use adc_t enum from PSP */
0,
/* The clock source, selects the best from BUSCLK and BUSCLK/2 */
ADC_CLK_BUSCLK_ANY,
/* The clock divisor for ADC. use the fastest one */
ADC_DIV_ANY,
/* ADC high speed control, see ADC_HSC enum */
ADC_HSC_NORMAL,
/* ADC low power control, see ADC_LPC enum */
ADC_LPC_NORMAL,
/* The calibration data pointer */
NULL,
/* ADC interrupt vector */
INT_ADC0,
/* ADC interrupt vector */
BSP_ADC0_VECTOR_PRIORITY,
/* PDB init structure */
&_bsp_pdb_init
};
但是,但是 这个硬件的初始化都没有涉及到最最底层的,I/O口的功能和AD通道的选择和配置????
再返回来分析一下ADC0的 任务,ADC0任务流使用的通道是:ADC_CHANNEL_DP3_DIFF:
大致的流程:
定义ADC通道和工作方式:
#define ADC_VALUE_MASK ((uint32_t)(0xff))
#define ADC_SAMPLE_FREQ ((uint32_t)(256))
#define ADC0_TABLE {ADC_CHANNEL_DP3_DIFF}////选择ADC通道是ADC_CHANNEL_DP3_DIFF
#define ADC0_TABLE_LEN (1)
//define if testing DIFF channel
#define TEST_DIFF_CH
以下为ADC0的初始化(初始化也没有看到有IO和通道选择的部分)??????????
typedef struct
{
ADC_CLOCK xAdcClock; //时钟
ADC_CLOCK_DIVSION xAdcClockDivsion; //时钟分频
ADC_ADACK xAdcAck; //异步时钟输出
ADC_DIFF xAdcDiff; //差分使能
ADC_LOWPOWER xAdcLowpower; //低功耗模式
ADC_MODE xAdcMode; //采样精度
ADC_LONG_SAMPLE xAdcLongSample; //长采样
ADC_LONG_SAMPLE_TIME xAdcLongSampleTime; //长采样时间
ADC_SPEED xAdcSpeed; //转换速度
ADC_TRIGGER xAdcTrigger; //触发方式
ADC_REFSEL xAdcRefsel; //参考电压
ADC_AVERAGE xAdcAverage; //硬件均值
ADC_AVERAGE_SELECT xAdcAverageSelect; //硬件均值采样数量
ADC_AVERAGE_CONTINUOUS xAdcAverageContinuous; //硬件均值连续转换次数
void (*old_isr)(pointer); //中断服务程序入口
pointer old_isr_data; //中断服务程序参数
}ADC_PARAMETER;
ADC_PARAMETER ux_Adc_Parameter;
ADC_StructInit(&ux_Adc_Parameter);//初始化ADC0,ADC0工作模式的初始化
再往下的机制大概就是利用PDB和2个DMA通道配合,分别片选ADC通道和读取ADC的采样结果,
并通过printfK串口打印(其中,这里用到的只有一个ADC通道,但从原理上做了多通道的考虑)
//配置DMA通道1,利用PDB和DMA原理机制是片选触发不同的ADC通道
ADC_DMACmd(ADC0, ENABLE);
DMA_PARAMETER ux_Dma_Parameter;
DMA_StructInit(&ux_Dma_Parameter);
ux_Dma_Parameter.xDmaSrcChannel = DMAMUX_SRC_CHANNEL_PDB;
ux_Dma_Parameter.u32SourceAddress = (uint32_t)&(u32_p_adc0_channel_table[0]);//跟AD通道有关的
ux_Dma_Parameter.u32DestinationAddress = (uint32_t)&(ADC0_SC1A);
ux_Dma_Parameter.u16SourceNextValueOffset = sizeof(uint32_t);
ux_Dma_Parameter.u16DestinationNextValueOffset = 0;
ux_Dma_Parameter.u8SourceAddressModulo = 0;
ux_Dma_Parameter.u8DestinationAddressModulo = 0;
ux_Dma_Parameter.xSourceDataSize = DMA_TRANSFER_SIZE_32_BIT;
ux_Dma_Parameter.xDestinationDataSize = DMA_TRANSFER_SIZE_32_BIT;
ux_Dma_Parameter.u32ByteTransferCount = sizeof(uint32_t);
ux_Dma_Parameter.u32LastSourceAddressAdjustment = -(ADC0_TABLE_LEN * ux_Dma_Parameter.u16SourceNextValueOffset);
ux_Dma_Parameter.u32LastDestinationAddressAdjustment = 0;
ux_Dma_Parameter.u16BufferSize = ADC0_TABLE_LEN;
DMA_Init(DMA_CHANNEL_0, DMAMUX, &ux_Dma_Parameter);
DMA_Cmd(DMA_CHANNEL_0, DMAMUX, ENABLE);
这里在配置DMA的的源地址的时候出现了跟ADC通道有关的 ux_Dma_Parameter.u32SourceAddress = (uint32_t)&(u32_p_adc0_channel_table[0]);
也就是ADC_CHANNEL_DP3_DIFF
但是也看不到有跟ADC通道的真正的最最底层的配置(ADCIO初始化和真正的ADC通道的选择的部分)
???????????????????????????????????????????????
/////////////////////////////////////////////////////////
//以下是配置DMA通道1 通过DMA读取ADC的打样结果
ux_Dma_Parameter.xDmaSrcChannel = DMAMUX_SRC_CHANNEL_ADC0;
ux_Dma_Parameter.u32SourceAddress = (uint32_t)&(ADC0_RA);
ux_Dma_Parameter.u32DestinationAddress = (uint32_t)&(ux_adc0_value.u16_p_all_value[0]);
ux_Dma_Parameter.u16SourceNextValueOffset = 0;
ux_Dma_Parameter.u16DestinationNextValueOffset = sizeof(uint16_t);
ux_Dma_Parameter.u8SourceAddressModulo = 0;
ux_Dma_Parameter.u8DestinationAddressModulo = 0;
ux_Dma_Parameter.xSourceDataSize = DMA_TRANSFER_SIZE_16_BIT;
ux_Dma_Parameter.xDestinationDataSize = DMA_TRANSFER_SIZE_16_BIT;
ux_Dma_Parameter.u32ByteTransferCount = sizeof(uint16_t);
ux_Dma_Parameter.u32LastSourceAddressAdjustment = 0;
ux_Dma_Parameter.u32LastDestinationAddressAdjustment = -((ADC0_TABLE_LEN*(ADC_VALUE_MASK + 1)) * ux_Dma_Parameter.u16DestinationNextValueOffset);
ux_Dma_Parameter.u16BufferSize = ADC0_TABLE_LEN*(ADC_VALUE_MASK + 1);
DMA_Init(DMA_CHANNEL_1, DMAMUX, &ux_Dma_Parameter);
DMA_Cmd(DMA_CHANNEL_1, DMAMUX, ENABLE);
///////////////到最后面就是取数据串口打印................
到整个过程下来,我都没有找到,也是让我迷惑的地方。。。。。。。最最底层的IO和 ADC通道的选择和配置的那部分硬件的初始化。
以下是 ADC0任务的DEMO代码:
谢谢大家!
#include <mqx.h>
#include <bsp.h>
#include "adc16.h"
#include "dma.h"
#include "app_dma.h"
#define ADC_VALUE_MASK ((uint32_t)(0xff))
#define ADC_SAMPLE_FREQ ((uint32_t)(256))
#define ADC0_TABLE {ADC_CHANNEL_DP3_DIFF}
#define ADC0_TABLE_LEN (1)
//define if testing DIFF channel
#define TEST_DIFF_CH
typedef union
{
struct
{
uint16_t u16_channel[ADC0_TABLE_LEN];
}ux_p_each_value[ADC_VALUE_MASK + 1];
uint16_t u16_p_all_value[ADC0_TABLE_LEN*(ADC_VALUE_MASK + 1)];
} ADC0_VALUE;
uint32_t u32_p_adc0_channel_table[ADC0_TABLE_LEN] = ADC0_TABLE;
ADC0_VALUE ux_adc0_value;
uint32_t cnt = 0;
/* Task IDs */
#define MAIN_TASK 5
/* Function prototypes */
extern void main_task(uint32_t);
const TASK_TEMPLATE_STRUCT MQX_template_list[] =
{
/* Task Index, Function, Stack, Priority, Name, Attributes, Param, Time Slice */
{MAIN_TASK, main_task, 2048, 8, "Main", MQX_AUTO_START_TASK, 0, 0 },
{0}
};
/*TASK*-----------------------------------------------------
**
** Task Name : main_task
** Comments :
**
*END*-----------------------------------------------------*/
void main_task
(
uint32_t initial_data
)
{
#ifdef TEST_DIFF_CH
short buf[ADC0_TABLE_LEN*(ADC_VALUE_MASK + 1)];
#endif
ADC_PARAMETER ux_Adc_Parameter;
ADC_StructInit(&ux_Adc_Parameter);
/* Before calibration, set hardware average to maximum and set ADC clock to be less than or equal to 4MHz,
using external reference VREFH = VDDA */
//ux_Adc_Parameter.xAdcAck = ADC_ADACK_ENABLE;
ux_Adc_Parameter.xAdcClock = ADC_CLOCK_BUSCLK;
ux_Adc_Parameter.xAdcClockDivsion = ADC_CLOCK_DIVSION_8;
ux_Adc_Parameter.xAdcMode = ADC_MODE_16_BIT;
ux_Adc_Parameter.xAdcLongSample = ADC_LONG_SAMPLE_ENABLE;
ux_Adc_Parameter.xAdcLongSampleTime = ADC_LONG_SAMPLE_TIME_6ADCK;
/* Select internal reference */
ux_Adc_Parameter.xAdcRefsel = ADC_REFSEL_INTERNAL;
/* Set ADC speed and low power mode to select ADACK value */
ux_Adc_Parameter.xAdcSpeed = ADC_SPEED_HIGH;
/* hardware average enable */
ux_Adc_Parameter.xAdcAverage = ADC_AVERAGE_ENABLE;
ux_Adc_Parameter.xAdcAverageContinuous = ADC_AVERAGE_CONTINUOUS_1;
ux_Adc_Parameter.xAdcAverageSelect = ADC_AVERAGE_SELECT_32;
ADC_Init(ADC0, &ux_Adc_Parameter);
ADC_Cal(ADC0);
/* hardware average enable */
//ux_Adc_Parameter.xAdcAverage = ADC_AVERAGE_DISABLE;
ux_Adc_Parameter.xAdcAverageSelect = ADC_AVERAGE_SELECT_4;
ADC_Init(ADC0, &ux_Adc_Parameter);
ADC_DMACmd(ADC0, ENABLE);
DMA_PARAMETER ux_Dma_Parameter;
DMA_StructInit(&ux_Dma_Parameter);
ux_Dma_Parameter.xDmaSrcChannel = DMAMUX_SRC_CHANNEL_PDB;
ux_Dma_Parameter.u32SourceAddress = (uint32_t)&(u32_p_adc0_channel_table[0]);
ux_Dma_Parameter.u32DestinationAddress = (uint32_t)&(ADC0_SC1A);
ux_Dma_Parameter.u16SourceNextValueOffset = sizeof(uint32_t);
ux_Dma_Parameter.u16DestinationNextValueOffset = 0;
ux_Dma_Parameter.u8SourceAddressModulo = 0;
ux_Dma_Parameter.u8DestinationAddressModulo = 0;
ux_Dma_Parameter.xSourceDataSize = DMA_TRANSFER_SIZE_32_BIT;
ux_Dma_Parameter.xDestinationDataSize = DMA_TRANSFER_SIZE_32_BIT;
ux_Dma_Parameter.u32ByteTransferCount = sizeof(uint32_t);
ux_Dma_Parameter.u32LastSourceAddressAdjustment = -(ADC0_TABLE_LEN * ux_Dma_Parameter.u16SourceNextValueOffset);
ux_Dma_Parameter.u32LastDestinationAddressAdjustment = 0;
ux_Dma_Parameter.u16BufferSize = ADC0_TABLE_LEN;
DMA_Init(DMA_CHANNEL_0, DMAMUX, &ux_Dma_Parameter);
DMA_Cmd(DMA_CHANNEL_0, DMAMUX, ENABLE);
ux_Dma_Parameter.xDmaSrcChannel = DMAMUX_SRC_CHANNEL_ADC0;
ux_Dma_Parameter.u32SourceAddress = (uint32_t)&(ADC0_RA);
ux_Dma_Parameter.u32DestinationAddress = (uint32_t)&(ux_adc0_value.u16_p_all_value[0]);
ux_Dma_Parameter.u16SourceNextValueOffset = 0;
ux_Dma_Parameter.u16DestinationNextValueOffset = sizeof(uint16_t);
ux_Dma_Parameter.u8SourceAddressModulo = 0;
ux_Dma_Parameter.u8DestinationAddressModulo = 0;
ux_Dma_Parameter.xSourceDataSize = DMA_TRANSFER_SIZE_16_BIT;
ux_Dma_Parameter.xDestinationDataSize = DMA_TRANSFER_SIZE_16_BIT;
ux_Dma_Parameter.u32ByteTransferCount = sizeof(uint16_t);
ux_Dma_Parameter.u32LastSourceAddressAdjustment = 0;
ux_Dma_Parameter.u32LastDestinationAddressAdjustment = -((ADC0_TABLE_LEN*(ADC_VALUE_MASK + 1)) * ux_Dma_Parameter.u16DestinationNextValueOffset);
ux_Dma_Parameter.u16BufferSize = ADC0_TABLE_LEN*(ADC_VALUE_MASK + 1);
DMA_Init(DMA_CHANNEL_1, DMAMUX, &ux_Dma_Parameter);
DMA_Cmd(DMA_CHANNEL_1, DMAMUX, ENABLE);
DMA_EnableRequest(DMAMUX, DMA_CHANNEL_0);
DMA_EnableRequest(DMAMUX, DMA_CHANNEL_1);
SIM_SCGC6 |= SIM_SCGC6_PDB_MASK;
PDB_SC_REG(PDB0_BASE_PTR) |= PDB_SC_PDBEN_MASK ;
PDB_SC_REG(PDB0_BASE_PTR) |= PDB_SC_TRGSEL(0xf) | PDB_SC_CONT_MASK;
PDB_MOD_REG(PDB0_BASE_PTR) = BSP_BUS_CLOCK / 50 / ADC_SAMPLE_FREQ;
PDB_IDLY_REG(PDB0_BASE_PTR) = 0;
PDB_SC_REG(PDB0_BASE_PTR) |= PDB_SC_LDOK_MASK;
PDB_SC_REG(PDB0_BASE_PTR) |= PDB_SC_DMAEN_MASK;
PDB_SC_REG(PDB0_BASE_PTR) |= PDB_SC_SWTRIG_MASK;
while(1)
{
for(long int i = 0; i < 8000000; i ++);
ADC_DMACmd(ADC0, DISABLE);
for(cnt = 0; cnt < ADC0_TABLE_LEN*(ADC_VALUE_MASK + 1); cnt++)
{
#ifdef TEST_DIFF_CH
//when ADC operate in differential mode, converted 16bit value is in 2's complement value
if((ux_adc0_value.u16_p_all_value[cnt])&0x8000)
buf[cnt] = -(~(ux_adc0_value.u16_p_all_value[cnt])+1);
else
buf[cnt] = ux_adc0_value.u16_p_all_value[cnt];
printf("%d\n", buf[cnt]);
#else
printf("%d\n", ux_adc0_value.u16_p_all_value[cnt]);
#endif
}
ADC_DMACmd(ADC0, ENABLE);
_time_delay(100);
}
//_task_block();
}
/* EOF */ |
|