首先SDK由platform平台代码和FreeRTOS操作系统代码组成
1.platform平台代码下,我们先分析CMSIS和devices,对应下图中倒数第二层:CMSIS-CORE and CMSIS-DSP
CMSIS:
● Cortex-M3内核及其设备文件(core_cm0.h + core_cm0.c)
─ 访问Cortex-M0内核及其设备:NVIC等
─ 访问Cortex-M0的CPU寄存器和内核外设的函数
devices:
● 微控制器专用头文件(device.h) - MK64F12.h
─ 指定中断号码(与启动文件一致)
─ 外设寄存器定义(寄存器的基地址和布局)
─ 控制微控制器其他特有的功能的函数(可选)
note:这里除了MK64F12.h,还有MK64F12_extension.h和MK64F12_features.h 。
MK64F12.h定义处理器各个外设的首地址和对应的寄存器访问宏定义
/** ADC - Register accessors */
#define ADC_SC1_REG(base,index) ((base)->SC1[index])
#define ADC_SC1_COUNT 2
#define ADC_CFG1_REG(base) ((base)->CFG1)
#define ADC_CFG2_REG(base) ((base)->CFG2)
#define ADC_R_REG(base,index) ((base)->R[index])
#define ADC_R_COUNT 2
#define ADC_CV1_REG(base) ((base)->CV1)
#define ADC_CV2_REG(base) ((base)->CV2)
#define ADC_SC2_REG(base) ((base)->SC2)
#define ADC_SC3_REG(base) ((base)->SC3)
#define ADC_OFS_REG(base) ((base)->OFS)
#define ADC_PG_REG(base) ((base)->PG)
#define ADC_MG_REG(base) ((base)->MG)
#define ADC_CLPD_REG(base) ((base)->CLPD)
#define ADC_CLPS_REG(base) ((base)->CLPS)
#define ADC_CLP4_REG(base) ((base)->CLP4)
#define ADC_CLP3_REG(base) ((base)->CLP3)
#define ADC_CLP2_REG(base) ((base)->CLP2)
#define ADC_CLP1_REG(base) ((base)->CLP1)
#define ADC_CLP0_REG(base) ((base)->CLP0)
#define ADC_CLMD_REG(base) ((base)->CLMD)
#define ADC_CLMS_REG(base) ((base)->CLMS)
#define ADC_CLM4_REG(base) ((base)->CLM4)
#define ADC_CLM3_REG(base) ((base)->CLM3)
#define ADC_CLM2_REG(base) ((base)->CLM2)
#define ADC_CLM1_REG(base) ((base)->CLM1)
#define ADC_CLM0_REG(base) ((base)->CLM0)
MK64F12_features.h 主要用宏对处理器上的外设的一些特性进行定义。拿ADC16来看,就是定义ADC16有没有FIFO,有没有PGA,有没有DMA等。
/** ADC16 module features */
/* @brief Has Programmable Gain Amplifier (PGA) in ADC (register PGA). */
#define FSL_FEATURE_ADC16_HAS_PGA (0)
/* @brief Has PGA chopping control in ADC (bit PGA[PGACHPb] or PGA[PGACHP]). */
#define FSL_FEATURE_ADC16_HAS_PGA_CHOPPING (0)
/* @brief Has PGA offset measurement mode in ADC (bit PGA[PGAOFSM]). */
#define FSL_FEATURE_ADC16_HAS_PGA_OFFSET_MEASUREMENT (0)
/* @brief Has DMA support (bit SC2[DMAEN] or SC4[DMAEN]). */
#define FSL_FEATURE_ADC16_HAS_DMA (1)
/* @brief Has differential mode (bitfield SC1x[DIFF]). */
#define FSL_FEATURE_ADC16_HAS_DIFF_MODE (1)
/* @brief Has FIFO (bit SC4[AFDEP]). */
#define FSL_FEATURE_ADC16_HAS_FIFO (0)
/* @brief FIFO size if available (bitfield SC4[AFDEP]). */
#define FSL_FEATURE_ADC16_FIFO_SIZE (0)
/* @brief Has channel set a/b multiplexor (bitfield CFG2[MUXSEL]). */
#define FSL_FEATURE_ADC16_HAS_MUX_SELECT (1)
/* @brief Has HW trigger masking (bitfield SC5[HTRGMASKE]. */
#define FSL_FEATURE_ADC16_HAS_HW_TRIGGER_MASK (0)
/* @brief Has calibration feature (bit SC3[CAL] and registers CLPx, CLMx). */
#define FSL_FEATURE_ADC16_HAS_CALIBRATION (1)
/* @brief Has HW averaging (bit SC3[AVGE]). */
#define FSL_FEATURE_ADC16_HAS_HW_AVERAGE (1)
/* @brief Has offset correction (register OFS). */
#define FSL_FEATURE_ADC16_HAS_OFFSET_CORRECTION (1)
/* @brief Maximum ADC resolution. */
#define FSL_FEATURE_ADC16_MAX_RESOLUTION (16)
/* @brief Number of SC1x and Rx register pairs (conversion control and result registers). */
#define FSL_FEATURE_ADC16_CONVERSION_CONTROL_COUNT (2)
MK64F12_extension.h 根据各个外设的各个寄存器的功能,定义对应于寄存器功能位的具体操作宏定义。
比如:
#define ADC_RD_SC1_DIFF(base, index) ((ADC_SC1_REG(base, index) & ADC_SC1_DIFF_MASK) >> ADC_SC1_DIFF_SHIFT)
就是读取ADC_SC1寄存器对应diff的位域的值。
#define ADC_INSTANCE_COUNT (2U) /*!< Number of instances of the ADC module. */
#define ADC0_IDX (0U) /*!< Instance number for ADC0. */
#define ADC1_IDX (1U) /*!< Instance number for ADC1. */
/*!
* @name Constants and macros for entire ADC_SC1 register
*/
/*@{*/
#define ADC_RD_SC1(base, index) (ADC_SC1_REG(base, index))
#define ADC_WR_SC1(base, index, value) (ADC_SC1_REG(base, index) = (value))
#define ADC_RMW_SC1(base, index, mask, value) (ADC_WR_SC1(base, index, (ADC_RD_SC1(base, index) & ~(mask)) | (value)))
#define ADC_SET_SC1(base, index, value) (ADC_WR_SC1(base, index, ADC_RD_SC1(base, index) | (value)))
#define ADC_CLR_SC1(base, index, value) (ADC_WR_SC1(base, index, ADC_RD_SC1(base, index) & ~(value)))
#define ADC_TOG_SC1(base, index, value) (ADC_WR_SC1(base, index, ADC_RD_SC1(base, index) ^ (value)))
/*@}*/
● 微控制器专用系统文件(system_device.c) – system_MK64F12.h + system_MK64F12 .c
─ 函数SystemInit,用来初始化微控制器
–函数 void SystemCoreClockUpdate (void); 用于获取内核时钟频率
─SystemCoreClock,该值代表系统时钟频率
─ 微控制器的其他功能(可选)
● 编译器启动代码(汇编或者C)(startup_device.s) - startup_MKL25Z4.s for Keil
─ 微控制器专用的中断处理程序列表(与头文件一致)
─ 弱定义(Weak)的中断处理程序默认函数(可以被用户代码覆盖)
2.分析drivers驱动层和hal硬件抽象层的区别和关联,这两个合起来对应于下图的Peripheral Drivers这一层。
hal下的代码是硬件抽象层代码,他通过调用MK64F12.h,还有MK64F12_extension.h里的寄存器操作宏定义来实现以下具体功能,比如初始化ADC16模块,配置通道等。
void ADC16_HAL_Init(ADC_Type * base)
{
ADC_WR_CFG1(base, 0U);
ADC_WR_CFG2(base, 0U);
ADC_WR_CV1(base, 0U);
ADC_WR_CV2(base, 0U);
ADC_WR_SC2(base, 0U);
ADC_WR_SC3(base, 0U);
#if FSL_FEATURE_ADC16_HAS_PGA
ADC_WR_PGA(base, 0U);
#endif /** FSL_FEATURE_ADC16_HAS_PGA */
}
drivers下的代码是对硬件抽象层hal代码的进一步抽象提升。
我们可以比较以下drivers和hal文件夹下的子目录
你会发现drivers比hal少了dmamux llwu mcg osc port rcm sim smc.
你会发现这些是adc16等这些共有模块或多或少都要交互依赖的模块。Adc16也需要时钟,所以要使ADC正常使用,我们必须设计osc mcg sim 时钟的设置。
adc16_status_t ADC16_DRV_Init(uint32_t instance, const adc16_converter_config_t *userConfigPtr)
{
assert(instance < ADC_INSTANCE_COUNT);
ADC_Type * base = g_adcBase[instance];
if (!userConfigPtr)
{
return kStatus_ADC16_InvalidArgument;
}
/** Enable clock for ADC. */
CLOCK_SYS_EnableAdcClock(instance);
/** Reset all the register to a known state. */
ADC16_HAL_Init(base);
ADC16_HAL_ConfigConverter(base, userConfigPtr);
/** Enable ADC interrupt in NVIC level.*/
INT_SYS_EnableIRQ(g_adcIrqId[instance] );
return kStatus_ADC16_Success;
}
从上面可以看到,ADC的正常初始化,不仅需要hal下adc的初始化 通道初始化,还需要时钟设置和中断设置。
3.FreeRTOS
操作系统应该调用驱动来实现对硬件的控制,上图中竟然平齐,这是什么道理???
操作系统其实不会调用驱动。而是由操作系统轮询的各个task会调用API。操作系统用到的硬件资源有timer。可以在工程里查找xPortStartScheduler这个函数,这里面会配置操作系统用到的定时器。这个定时器就不能它用了。
详细的FreeRTOS任务切换解析可以参考下面的博客:
http://blog.sina.com.cn/s/blog_5f0bed160100tqnu.html
main()
{
prvSetupHardware();//初始化硬件(处理器IO,初始化等)
//创建第一个任务 vTestTask.任务创建参考----FreeRTOS任务管理与控制--------
xTaskCreate( vTestTask, ( signed portCHAR *) "Test", configMINIMAL_STACK_SIZE, NULL, (tskIDLE_PRIORITY+1), NULL);
//开启内核运行,调度便由此开始。
vTaskStartScheduler();
}
void main()
{
/** initialize the hardware */
PE_low_level_init();
/** disable write buffering end enable ARM exceptions */
HEXIWEAR_EnableExceptions();
/** initialize the startup task */
HEXIWEAR_Init();
/** start RTOS scheduler */
HEXIWEAR_Start();
while (1) {}
}