在做MCU使用USB通信協定與PC端溝通的實驗時,發現在linux與windows上有了不同的狀況。在windows用Bus Hound與自己寫的程式,都能正常地抓到MCU端丟出來的資料,但在Linux上卻有狀況。
最後追到了Report Descriptor描述表中的ReportID這個項目,發現MUC端在Report Descriptor中有定義ReportID的話,送出的Data必須在最前面加上ReportID,不然Linux端會抓不到資料,後來去翻了HID1_11的文件,終於搞清楚是怎麼一回事了。
在HID1_11文件5.6 Reports有提到Report ID的特性:
1.Report ID items are used to indicate which data fields are represented in each report structure.
2.A Report ID item
tag assigns a 1-byte identification prefix to each report transfer.
3.If no Report ID item
tags are present in the Report descriptor,
it can be assumed that only one Input, Output, and
Feature report structure.
這裡總結一下以上的描述,當你的Report Descriptor只有一個Input, Output, 或是 Feature的話,可以不用定義Report ID,但是有用到Report ID的話,必須在每一個report transfer最前面加入一個Byte的Report ID參數。
2016年7月27日 星期三
2016年7月24日 星期日
STM32F411xC 基礎教學 :Timer使用方式
STM32F411xC/E Timer可分為以下三組:
1. Advanced-control timer(TIM1)
2.General-purpose timers(TIM2 to TIM5)
3.General-purpose timers(TIM9 to TIM11)
ps. TIM8 在STM32F411xC/E中是不能用的。
這三組有各自相對應的block diagram,根據使用不同的AHB/APB2或AHB/APB1,也會對時間計算有不同的結果,細節可自行參考RM0383 Reference manual。
STM32 Timer 每次進入中斷時間間隔計算方式:
((1+TIM_Prescaler) / 系統頻率)*(1+TIM_Period) =
((1+9599)/96Mhz) * (1+9999) = 1 sec。
main function:
Debug GPIO(PC15) init:
TIM2 init:
TIM2 IRQHandler:
驗證:
下圖為邏輯分析儀測量的結果,由圖中可看出PC15每一秒鐘會觸發一次,符合我們所預期的時間。
1. Advanced-control timer(TIM1)
2.General-purpose timers(TIM2 to TIM5)
3.General-purpose timers(TIM9 to TIM11)
ps. TIM8 在STM32F411xC/E中是不能用的。
這三組有各自相對應的block diagram,根據使用不同的AHB/APB2或AHB/APB1,也會對時間計算有不同的結果,細節可自行參考RM0383 Reference manual。
STM32 Timer 每次進入中斷時間間隔計算方式:
((1+TIM_Prescaler) / 系統頻率)*(1+TIM_Period) =
((1+9599)/96Mhz) * (1+9999) = 1 sec。
main function:
int main(void)
{
RCC_ClocksTypeDef RCC_Clocks;
RCC_GetClocksFreq(&RCC_Clocks);
debug_io_init();
TIM2_Init();
/* Infinite loop */
while (1)
}
Debug GPIO(PC15) init:
void debug_io_init( void )
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOC, ENABLE );
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_Init( GPIOC, &GPIO_InitStructure );
GPIO_ResetBits(GPIOC, GPIO_Pin_15);
GPIO_SetBits(GPIOC, GPIO_Pin_15);
}
TIM2 init:
void TIM2_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* TIM2 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* Enable the TIM2 gloabal Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 10000-1;
TIM_TimeBaseStructure.TIM_Prescaler = 9600-1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM2, ENABLE);
}
TIM2 IRQHandler:
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
{
GPIO_ResetBits(GPIOC, GPIO_Pin_15);
GPIO_SetBits(GPIOC, GPIO_Pin_15);
GPIO_ToggleBits(GPIOC, GPIO_Pin_0);
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}
驗證:
下圖為邏輯分析儀測量的結果,由圖中可看出PC15每一秒鐘會觸發一次,符合我們所預期的時間。
2016年7月21日 星期四
STM32F411xC 基礎教學 :SysTick使用方式
本篇基於STM32F411xC平台,紀錄SysTick的使用方式。
實驗說明:
使用GPIO(PC15)來觀察程式進入SysTick_Handler,到下一次進入SysTick_Handler的時間。
Main function:
SysTick_Handler function:
使用邏輯分析儀觀察GPIO:
由下圖觀察到,由於我們在SysTick_Handler中有做將GPIO拉high->low的動作,因此觀察GPIO high的間格時間,即可知道SysTick是否依我們的設計每10m觸發一次。

實驗說明:
使用GPIO(PC15)來觀察程式進入SysTick_Handler,到下一次進入SysTick_Handler的時間。
Main function:
int main(void)
{
RCC_ClocksTypeDef RCC_Clocks;
RCC_GetClocksFreq(&RCC_Clocks);
SysTick_Config(960000+1);//10ms中斷一次
while ( 1 ) {
if (flag_10ms_period){
flag_10ms_period = 0;
//每10ms要執行的function
}
}
}
SysTick_Handler function:
extern volatile uint8_t flag_10ms_period;
void SysTick_Handler(void)
{
GPIO_SetBits(GPIOC, GPIO_Pin_15);
flag_10ms_period = 1;
GPIO_ResetBits(GPIOC, GPIO_Pin_15);
}
SysTick會依照你使用MCU的系統頻率來計算中斷次數,下圖為STM32F411xC的SysClk,這次範例要計算每10ms中斷一次,計算方式為96000MHz(實體頻率) * 10,並在main.c中加入SysTick_Config(96000*10)。
| STM32F411xC Sysclk |
由下圖觀察到,由於我們在SysTick_Handler中有做將GPIO拉high->low的動作,因此觀察GPIO high的間格時間,即可知道SysTick是否依我們的設計每10m觸發一次。

2016年7月20日 星期三
STM32F411xC 基礎教學 : Button與 LED使用方式
本篇基於STM32F411xC平台,記錄板端Button與Led的使用方式。
實驗說明:
按下Button1(PD2)點亮Led2(PC0),Button2(PC12)點亮Led5(PC1)。
Button 初始化:
LED 初始化:
Main function:
實驗說明:
按下Button1(PD2)點亮Led2(PC0),Button2(PC12)點亮Led5(PC1)。
Button 初始化:
//button1:PD2
//button2:PC12
void Btn_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOD, ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_Init( GPIOD, &GPIO_InitStructure );
RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOC, ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_Init( GPIOC, &GPIO_InitStructure );
}
LED 初始化:
//LED2:PC0
//LED5:PC1
//LED3:PC2
//LED4:PC3
void gpio_led_config( void )
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOC, ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init( GPIOC, &GPIO_InitStructure );
}
Main function:
int main(void)
{
RCC_ClocksTypeDef RCC_Clocks;
RCC_GetClocksFreq(&RCC_Clocks);
Btn_Init();
gpio_led_config();
while ( 1 ) {
//Sw1
if (GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_2) == 0){
//turn on PC0:LED2
GPIO_SetBits(GPIOC, GPIO_Pin_0);
}else{
//turn off PC0:LED2
GPIO_ResetBits(GPIOC, GPIO_Pin_0);
}
//Sw2
if (GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_12) == 0){
GPIO_SetBits(GPIOC, GPIO_Pin_1);
}else{
GPIO_ResetBits(GPIOC, GPIO_Pin_1);
}
}
}
訂閱:
文章 (Atom)
