開發(fā)環(huán)境:
開發(fā)板:正點(diǎn)原子F407探索者
代碼生成工具:STM32CubeMX v5.4.0
IDE: eclipse + ac6工具鏈
實(shí)現(xiàn)功能:
單片機(jī)可以通過usb接口和EC20的AT指令虛擬串口通訊。
為了方便測(cè)試,配置串口2,將 模塊->單片機(jī) 方向的數(shù)據(jù)通過串口2發(fā)送到電腦,將電腦通過串口工具發(fā)送到單片機(jī)的數(shù)據(jù),轉(zhuǎn)發(fā)給模塊。
開始
1、使用STM32CubeMX配置工程,生成基礎(chǔ)代碼
1.1.1 配置晶振
1.1.2 配置時(shí)鐘
1.2.1 配置串口2
1.2.2 配置DMA
1.2.3 開串口中斷
1.3.1 配置USB Host_Only,不使用VBUS SOF
1.3.2 在Middleware中選擇USB_HOST
將Class for FS IP 配置為 Communication Host Class (Virtual Port Com)
因?yàn)橐七h(yuǎn)EC20模塊連接后,配置描述符下一共有5個(gè) Interface , 并且 Interface 中至多有3個(gè)Endpoint(下面簡(jiǎn)稱Ep)。所以 注意: USBH_MAX_NUM_ENDPOINTS 需配置 >3 , USBH_MAX_NUM_INTERFACES 需配置 >5 。
1.4 配置USB供電引腳
查詢探索者F4開發(fā)板原理圖可知USB-HOST供電引腳為 PA15 ,在右側(cè)雙擊芯片引腳配置為輸出模式。
1.5 在左側(cè)GPIO中進(jìn)一步將 PA15 配置為高電平輸出。并對(duì) 串口2 和 usb 引腳進(jìn)行配置。
1.6 sys->debug方式,選擇 Trace Asynchronous Sw 。
1.7 點(diǎn)擊Project Manager 配置項(xiàng)目名稱,生成代碼。
如果使用MDK5 或 其他IDE可以在 Toolchain / IDE 中切換。
1.8 配置完成,點(diǎn)擊右上角 GENERATE CODE 。
2、修改cubemx生成的代碼
2.1 修改CDC_Class結(jié)構(gòu)體,將 USB_CDC_CLASS 修改為 0xFF
USBH_ClassTypeDef CDC_Class =
{
"CDC",
0xFF,
USBH_CDC_InterfaceInit,
USBH_CDC_InterfaceDeInit,
USBH_CDC_ClassRequest,
USBH_CDC_Process,
USBH_CDC_SOFProcess,
NULL,
};
2.2 修改usbh_cdc.c 中的 USBH_CDC_InterfaceInit 函數(shù)
static USBH_StatusTypeDef USBH_CDC_InterfaceInit(USBH_HandleTypeDef *phost)
{
USBH_StatusTypeDef status = USBH_FAIL;
uint8_t interface;
CDC_HandleTypeDef *CDC_Handle;
// 默認(rèn)系統(tǒng)配置標(biāo)準(zhǔn)CDC接口
// interface = USBH_FindInterface(phost,
// USB_CDC_CLASS,
// ABSTRACT_CONTROL_MODEL,
// COMMON_AT_COMMAND);
/**
* 注:
* cubemx生成的例程中,標(biāo)準(zhǔn)的CDC類設(shè)備,1個(gè)配置描述符中需要2接口
* 其中一個(gè)為Communication Interface Class, 該接口需要一個(gè)方向?yàn)閕n的Ep
* 另外一個(gè)為Data Interface Class, 該接口需要一個(gè)方向?yàn)閕n的Ep和一個(gè)方向?yàn)閛ut的Ep
* 所以USBH_CDC_InterfaceInit函數(shù),調(diào)用了兩次USBH_FindInterface函數(shù)
* 查找兩個(gè)匹配的Interface, 分別進(jìn)行配置
*
* USB-TTL串口工具,debug狀態(tài)下查詢?cè)O(shè)備描述符結(jié)構(gòu)體中,只有一個(gè)接口
* 但是該接口擁有3個(gè)Ep, 2個(gè)方向?yàn)閕n, 1個(gè)方向?yàn)閛ut.
* 由此猜測(cè),串口工具并沒有將Interface分開
* 經(jīng)測(cè)試, Communication Interface使用的Ep為2, Data Interface使用Ep0,1
*
* Ec20模塊,可以讀到5個(gè)Interface,但是只有Interface 1 2 3 有3個(gè)Ep,0 和 4 只有2個(gè)Ep
* 經(jīng)測(cè)試,接口AT指令的串口Interface為 2.
* Interface 2中,Communication Interface使用的Ep為0
* Data Interface使用的Ep為1 和 2
*/
// USB-TTL串口工具接口配置
// interface = USBH_FindInterface(phost,
// USER_USB_CDC_CLASS,
// DIRECT_LINE_CONTROL_MODEL, 02);
// 移遠(yuǎn)4G模塊接口配置
interface = USBH_FindInterfaceIndex(phost, 2, 0);
if (interface == 0xFFU) /* No Valid Interface */
{
USBH_DbgLog("Cannot Find the interface for Communication Interface Class.",
phost->pActiveClass->Name);
}
else
{
USBH_SelectInterface(phost, interface);
phost->pActiveClass->pData = (CDC_HandleTypeDef*) USBH_malloc(
sizeof(CDC_HandleTypeDef));
CDC_Handle = (CDC_HandleTypeDef*) phost->pActiveClass->pData;
/*Collect the notification endpoint address and length*/
if (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress
& 0x80U)
{
CDC_Handle->CommItf.NotifEp =
phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress;
CDC_Handle->CommItf.NotifEpSize =
phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize;
}
/*Allocate the length for host channel number in*/
CDC_Handle->CommItf.NotifPipe = USBH_AllocPipe(phost,
CDC_Handle->CommItf.NotifEp);
/* Open pipe for Notification endpoint */
USBH_OpenPipe(phost, CDC_Handle->CommItf.NotifPipe,
CDC_Handle->CommItf.NotifEp, phost->device.address, phost->device.speed,
USB_EP_TYPE_INTR, CDC_Handle->CommItf.NotifEpSize);
USBH_LL_SetToggle(phost, CDC_Handle->CommItf.NotifPipe, 0U);
// 默認(rèn)系統(tǒng)配置標(biāo)準(zhǔn)CDC接口
// interface = USBH_FindInterface(phost,
// DATA_INTERFACE_CLASS_CODE,
// RESERVED,
// NO_CLASS_SPECIFIC_PROTOCOL_CODE);
if (interface == 0xFFU) /* No Valid Interface */
{
USBH_DbgLog("Cannot Find the interface for Data Interface Class.",
phost->pActiveClass->Name);
}
else
{
/*Collect the class specific endpoint address and length*/
if (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[2].bEndpointAddress
& 0x80U)
{
CDC_Handle->DataItf.InEp =
phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[2].bEndpointAddress;
CDC_Handle->DataItf.InEpSize =
phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[2].wMaxPacketSize;
}
else
{
CDC_Handle->DataItf.OutEp =
phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[2].bEndpointAddress;
CDC_Handle->DataItf.OutEpSize =
phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[2].wMaxPacketSize;
}
if (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].bEndpointAddress
& 0x80U)
{
CDC_Handle->DataItf.InEp =
phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].bEndpointAddress;
CDC_Handle->DataItf.InEpSize =
phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].wMaxPacketSize;
}
else
{
CDC_Handle->DataItf.OutEp =
phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].bEndpointAddress;
CDC_Handle->DataItf.OutEpSize =
phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].wMaxPacketSize;
}
/*Allocate the length for host channel number out*/
CDC_Handle->DataItf.OutPipe = USBH_AllocPipe(phost,
CDC_Handle->DataItf.OutEp);
/*Allocate the length for host channel number in*/
CDC_Handle->DataItf.InPipe = USBH_AllocPipe(phost,
CDC_Handle->DataItf.InEp);
/* Open channel for OUT endpoint */
USBH_OpenPipe(phost, CDC_Handle->DataItf.OutPipe,
CDC_Handle->DataItf.OutEp, phost->device.address, phost->device.speed,
USB_EP_TYPE_BULK, CDC_Handle->DataItf.OutEpSize);
/* Open channel for IN endpoint */
USBH_OpenPipe(phost, CDC_Handle->DataItf.InPipe, CDC_Handle->DataItf.InEp,
phost->device.address, phost->device.speed,
USB_EP_TYPE_BULK, CDC_Handle->DataItf.InEpSize);
CDC_Handle->state = CDC_IDLE_STATE;
USBH_LL_SetToggle(phost, CDC_Handle->DataItf.OutPipe, 0U);
USBH_LL_SetToggle(phost, CDC_Handle->DataItf.InPipe, 0U);
status = USBH_OK;
}
}
return status;
}
修改原因請(qǐng)參見代碼中的注釋
2.3 修改 USBH_CDC_ClassRequest 函數(shù)
static USBH_StatusTypeDef USBH_CDC_ClassRequest(USBH_HandleTypeDef *phost)
{
USBH_StatusTypeDef status = USBH_FAIL;
CDC_HandleTypeDef *CDC_Handle =
(CDC_HandleTypeDef*) phost->pActiveClass->pData;
// /*Issue the get line coding request*/
// status = GetLineCoding(phost, &CDC_Handle->LineCoding);
CDC_Handle->data_rx_state = CDC_IDLE;
CDC_Handle->data_tx_state = CDC_IDLE;
CDC_Handle->LineCoding.b.bCharFormat = 0;
CDC_Handle->LineCoding.b.bDataBits = 8;
CDC_Handle->LineCoding.b.bParityType = 0;
CDC_Handle->LineCoding.b.dwDTERate = 115200;
status = USBH_OK;
if (status == USBH_OK)
{
phost->pUser(phost, HOST_USER_CLASS_ACTIVE);
}
return status;
}
因?yàn)樽x取不到LineCoding相關(guān)參數(shù),所以在這里進(jìn)行相關(guān)參數(shù)的手動(dòng)設(shè)置。
具體讀不到的原因,我也不是很清楚。因?yàn)榇谶B接電腦之后,也是通過串口工具手動(dòng)選擇的波特率。所以猜測(cè)這里也是同樣的道理,需要自己手動(dòng)設(shè)置。希望各位指正。
2.4 在 usb_host.c 中添加接收代碼。
在 MX_USB_HOST_Process 函數(shù)中添加接收代碼。
// RecData.buf 為數(shù)據(jù)緩存區(qū)首地址
// UART_BUF_LEN 為數(shù)據(jù)緩存區(qū)長(zhǎng)度
// 可以根據(jù)自己的需要自定義
void MX_USB_HOST_Process(void)
{
CDC_HandleTypeDef *CDC_Handle = hUsbHostFS.pActiveClass->pData;
/* USB Host Background task */
USBH_Process(&hUsbHostFS);
if (hUsbHostFS.gState == HOST_CLASS)
{
if (CDC_Handle->data_rx_state == CDC_IDLE)
{
USBH_CDC_Receive(&hUsbHostFS, RecData.buf, UART_BUF_LEN);
}
}
}
2.5 在 main.c 或者其他需要的位置,添加 USBH_CDC_ReceiveCallback 函數(shù)。(原函數(shù)為弱函數(shù),用戶添加后會(huì)將原函數(shù)覆蓋)
// 這里我設(shè)置了一個(gè)read_flag表示數(shù)據(jù)未讀,別處代碼有用到
// uart_send是我封裝的一個(gè)串口發(fā)送函數(shù),將數(shù)據(jù)通過串口2轉(zhuǎn)發(fā)電腦
void USBH_CDC_ReceiveCallback(USBH_HandleTypeDef *phost)
{
RecData.len_rec = USBH_CDC_GetLastReceivedDataSize(phost);
RecData.read_flag = 0;
uart_send(&uart2, Recbuff.buf, len);
}
2.6 在 main() while(1) 中等待接收串口2發(fā)過來的數(shù)據(jù),長(zhǎng)度不為0就調(diào)用usb發(fā)送函數(shù),將數(shù)據(jù)發(fā)送出去。
while (1)
{
/* USER CODE END WHILE */
MX_USB_HOST_Process();
/* USER CODE BEGIN 3 */
switch (Appli_state)
{
case APPLICATION_READY:
len_rec = uart_receive(&uart2, main_buf, 1);
if (len_rec != 0)
{
USBH_CDC_Transmit(&hUsbHostFS, main_buf, len_rec);
}
break;
case APPLICATION_DISCONNECT:
ec20.init_flag = 0;
break;
default:
break;
}
3、 編譯下載運(yùn)行,成功發(fā)送at并接收到at指令回復(fù)。
總結(jié)
整個(gè)USB-HOST配置過程,難點(diǎn)在于對(duì) usbh_cdc.c 文件的修改。網(wǎng)上做stm32
usb-host-cdc的資料很少。我是先配置連接usb串口工具成功以后,對(duì)usb通訊的配置描述符、接口描述符、端點(diǎn)描述符有了一定的了解。之后才進(jìn)行的 ec20 模塊配置。希望可以對(duì)跟我一樣的新手有所幫助。
因?yàn)?EC20 模塊 at指令 配置部分還沒寫完,就先不放工程上來了。
上一篇:STM32CubeMx學(xué)習(xí)之-NVIC
下一篇:STM32CubeMx開發(fā)之路—3發(fā)送USART數(shù)據(jù)和printf重定向
推薦閱讀
史海拾趣
設(shè)計(jì)資源 培訓(xùn) 開發(fā)板 精華推薦
- Microchip 升級(jí)數(shù)字信號(hào)控制器(DSC)產(chǎn)品線 推出PWM 分辨率和 ADC 速度業(yè)界領(lǐng)先的新器件
- 意法半導(dǎo)體STM32MP23x:突破成本限制的工業(yè)AI應(yīng)用核心
- 意法半導(dǎo)體推出用于匹配遠(yuǎn)距離無線微控制器STM32WL33的集成的匹配濾波芯片
- ESP32開發(fā)板連接TFT顯示屏ST7789跳坑記
- 如何讓ESP32支持analogWrite函數(shù)
- LGVL配合FreeType為可變字體設(shè)置字重-ESP32篇
- 使用樹莓派進(jìn)行 ESP32 Jtag 調(diào)試
- ESP32怎么在SPIFFS里面存儲(chǔ)html,css,js文件,以及網(wǎng)頁(yè)和arduino的通訊
- ESP32 freeRTOS使用測(cè)試
- 上汽大眾:汽車網(wǎng)絡(luò)安全漏洞防護(hù)
- 恩智浦推出全新電池控制IC系列 助力新能源解決方案發(fā)展
- 全球首條GWh級(jí)新型固態(tài)電池生產(chǎn)線樣件下線
- 總投資455億元!三大動(dòng)力電池項(xiàng)目齊刷進(jìn)度條
- 現(xiàn)代汽車韓國(guó)建氫燃料電池廠,2028年投產(chǎn)
- 6月融資一覽:智能汽車芯片、第三代半導(dǎo)體、機(jī)器人成資本焦點(diǎn)
- 艙駕一體“點(diǎn)燃”新戰(zhàn)事
- 汽車智能化2.0引爆「萬億蛋糕」,誰在改寫游戲規(guī)則?
- 2025研華智能系統(tǒng)產(chǎn)業(yè)伙伴峰會(huì)成功舉辦
- 意法半導(dǎo)體公布2025年第二季度財(cái)報(bào)和電話會(huì)議時(shí)間安排
- 下載白皮書 答題贏好禮|TE《智能監(jiān)控應(yīng)用連接解決方案指南》
- 贏京東卡 室內(nèi)空氣隱患大作戰(zhàn)——英飛凌XENSIV™PAS CO2傳感器
- 下載汽車電氣化精品文章,贏【體脂秤、羅技鼠標(biāo)、手持風(fēng)扇】,開啟MPS汽車技術(shù)進(jìn)階之旅!
- CadenceLIVE China 2022中國(guó)線上用戶大會(huì) 報(bào)名中!
- 免費(fèi)測(cè)評(píng)|ESP32-S2-Kaluga-1新型多媒體開發(fā)板,靈活拆裝,滿足多種需求
- 【有獎(jiǎng)下載】英飛凌《時(shí)尚小家電功率器選型指南》,詳解兼具強(qiáng)大功能與潮流款式的小家電設(shè)計(jì)!
- 有獎(jiǎng)直播 | 微軟 Azure Sphere助力穩(wěn)定,安全和靈活的物聯(lián)網(wǎng)解決方案
- ADI軟件定義無線電(SDR)專題文章
- 富士通白皮書有獎(jiǎng)下載|FRAM高性能存儲(chǔ)器優(yōu)化車載電子系統(tǒng)
- 舒伯特全自動(dòng)包裝讓 J?germeister銷量節(jié)節(jié)走高
- 燒光84億造不出量產(chǎn)車!拜騰咋這么會(huì)玩
- 重要里程碑,3GPP宣布R16標(biāo)準(zhǔn)完成
- OPPO聯(lián)手沃達(dá)豐、愛立信,參與英國(guó)首個(gè)5G SA網(wǎng)絡(luò)搭建
- 英國(guó)擬今年逐步淘汰華為5G設(shè)備:已禁止英國(guó)5G網(wǎng)路采用
- 陽(yáng)光電源儲(chǔ)能系統(tǒng)發(fā)往馬爾代夫26座島嶼
- Impossible Aerospace獲940萬美元A輪融資 讓無人機(jī)實(shí)現(xiàn)2小時(shí)續(xù)航
- Yole:傳感器和執(zhí)行器市場(chǎng)2023年將超1000億美元
- 北斗界的小華為
- 瑞薩電子收購(gòu)IDT,加強(qiáng)嵌入式解決方案全球領(lǐng)先地位