首先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) {}
}