「usb_dev.c」での HardFault の回避方法を教えてください。
よろしくお願いします。
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
KSDK_1.0.0 インストール => インストール後再起動
インストール先
D:\Temp\Freescale\ksdk_1.0.0
カスタム設定で以下をチェック
KSDK_1.0.0
FreeRTOS_V8.0.0
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
IAR Embedded Workbench IDE を起動。
以下のワークスペースを開く
D:\Temp\Freescale\KSDK_1.0.0\usb\example\device\cdc\
virtual_com\sdk\iar\dev_cdc_virtual_com_frdmk64f120m_freertos
dev_cdc_virtual_com_frdmk64f120m_freertos.eww
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
Make (DebugモードでMakeする。(とりあえず))
ksdk_freertos_lib - Debug エラー: 0, ワーニング: 0
以下のオプション設定を変更する。
一般オプション
「MISRA-C2004」タブ
MISRA-Cを有効にする(E): チェック有り -> チェックを外す。
usbd_sdk_frdmk64f120m_freertos - Debug エラー: 0, ワーニング: 29
オプションの変更は無し。
dev_cdc_virtual_com_frdmk64f120_freertos - Debug エラー: 0, ワーニング: 0
オプションの変更は無し。
右クリックして「アクティブに設定」を選択する。
<Source code「virtual_com.c」の変更>
1. sources配下の virtual_com.c の 392行目からの「void Virtual_Com_App(void)」
に以下(001)または(002)を追加する。(追加のパターンは(001)=正常と(002)=異常の 2種類)
2. sources配下の virtual_com.c の最後尾に
「int str_copy(uint8_t dst_str[], uint8_t src_str[])」と
「int strlen(uint8_t char_count[])」
を追加する。
3. 「Virtual_Com_App(void)」より前に以下を定義する。
「int str_copy(uint8_t dst_str[], uint8_t src_str[]);」
「int strlen(uint8_t char_count[]);」
をそれぞれMakeする。
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
デバッガの設定
1. dev_cdc_virtual_com_frdmk64f120_freertos - Debug を右クリックしてオプションを開く
2. カテゴリのデバッガを選択して、設定タブの ドライバ(D):で「I-jet/JTAGjet」を選択する。
3. カテゴリのデバッガ配下の「I-jet/JTAGjet」を選択を選択して設定タブのリセット(R):を
ハードウェアに設定する。
4. 同じく「I-jet/JTAGjet」の設定タブの ターゲット電源の「プローブから供給(F)」
のチェックを外す。
5. 「JTAG/SWD」の設定タブの インタフエースで「SWD(S)」を選択する。
6. OKを押してオプション設定を終了する。
7. コンパイル後、デバッガを起動させ、mainで停止後、一度ハードリセットを実行する。、
再度mainで停止した箇所からプログラムを「実行」させる。(この時点ではまだ
TeraTermは起動しない。)
8. TeraTermを起動させてUSB-Serialドライバで指定したCOMポート番号に接続。
(PCにはあらかじめ「mchpcdc.inf」にてドライバを設定しておく。)
☆ ハードリセットは、TeraTermを終了させてから実施する。
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
確認
1. 001 の場合は、Enterをキーボートから押下すると改行後に「Prompt> 」が表示される。
回数に制限が無く正常に応答する。(表示は正常)
┌──────────────────
│
│Prompt>
│Prompt>
│Prompt>
│Prompt>
│ :
│
2. 002 の場合は、Enterをキーボートから押下すると、以下のように表示され、
11回目に以下の場所で止まる。(表示も異常)
┌──────────────────
│
│Prompt> PrPrompt> PrPrompt>
│Prompt> PrPrompt>
│Prompt>
│Prompt>
│Prompt>
│Prompt> PrPrompt>
│
3.停止位置
1. 以下の「HardFault_Handler」の下の「B .」でカーソルが止まっている。
startup_MK64F12.s の385行目
:
PUBWEAK NMI_Handler
SECTION .text:CODE:REORDER:NOROOT(1)
NMI_Handler
B .
PUBWEAK HardFault_Handler
SECTION .text:CODE:REORDER:NOROOT(1)
HardFault_Handler
B . <= 385 行目
PUBWEAK MemManage_Handler
SECTION .text:CODE:REORDER:NOROOT(1)
MemManage_Handler
B .
:
2. 逆アセンブリのウインドウでは、以下の「0x5bc6: 0xe7fe」でカーソルが止まっている。
:
HardFault_Handller:
0x5bc6: 0xe7fe B.N HardFault_Handller ; 0x5bc6
:
4. 停止直前の実行箇所
以下のコード実行時に停止する。
ファイル名: usb_dev.c
実行命令:
OS_dcache_flush_mlines((void*)buff_ptr,size); 内の
:
/* Initialize the new transfer descriptor */
xd_ptr->ep_num = ep_num;
xd_ptr->bdirection = USB_SEND; <= 2回目の実行後停止(ステップ実行) 1118行目
xd_ptr->wtotallength = size;
xd_ptr->wstartaddress = buff_ptr;
xd_ptr->wsofar = 0;
xd_ptr->bstatus = USB_STATUS_TRANSFER_ACCEPTED;
:
☆ Hard_Faultの回避方法について教えてください。
よろしくお願いします。
/*(001)***************************************************************************/
void Virtual_Com_App(void)
{
/* User Code */
if(g_recv_size)
{
int32_t i;
/* Copy Buffer to Send Buff */
for (i = 0; i < g_recv_size; i++)
{
//printf("Copied: %c\n", g_curr_recv_buf[i]);
g_curr_send_buf[g_send_size++] = g_curr_recv_buf[i];
}
g_recv_size = 0;
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <ここから追加> */
str_copy(g_curr_send_buf, "\r\nPrompt> ");
g_send_size = 10;
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <追加はここまで> */
}
if(g_send_size)
{
uint8_t error;
uint8_t size = g_send_size;
g_send_size = 0;
error = USB_Class_CDC_Send_Data(g_app_handle, DIC_BULK_IN_ENDPOINT,
g_curr_send_buf, size);
if(error != USB_OK)
{
/* Failure to send Data Handling code here */
}
}
return;
}
/*(002)***************************************************************************/
void Virtual_Com_App(void)
{
/* User Code */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <ここから追加> */
static int CmdSendRequest;
if (CmdSendRequest == 1) {
CmdSendRequest = 0;
str_copy(g_curr_send_buf, "Prompt> ");
g_send_size = 8;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <追加はここまで> */
if(g_recv_size)
{
int32_t i;
/* Copy Buffer to Send Buff */
for (i = 0; i < g_recv_size; i++)
{
//printf("Copied: %c\n", g_curr_recv_buf[i]);
g_curr_send_buf[g_send_size++] = g_curr_recv_buf[i];
}
g_recv_size = 0;
CmdSendRequest = 1; /* - - - - - - - - - - - - - - - <ここを追加> */
}
if(g_send_size)
{
uint8_t error;
uint8_t size = g_send_size;
g_send_size = 0;
error = USB_Class_CDC_Send_Data(g_app_handle, DIC_BULK_IN_ENDPOINT,
g_curr_send_buf, size);
if(error != USB_OK)
{
/* Failure to send Data Handling code here */
}
}
return;
}
/*****************************************************************************/
int str_copy(uint8_t dst_str[], uint8_t src_str[]);
int strlen(uint8_t char_count[]);
int str_copy(uint8_t dst_str[], uint8_t src_str[])
{
int i;
int n;
n = strlen(src_str);
for (i = 0; i < n; i++) {
dst_str[i] = src_str[i];
}
dst_str[i] = 0x00;
return n;
}
/*****************************************************************************/
int strlen(uint8_t char_count[])
{
int i;
int c;
c = 0;
for (i = 0; i < 255 ; i++) {
if (char_count[i] == 0x00) {
c = i;
i = 255;
}
}
return c;
}
/*****************************************************************************/
Solved! Go to Solution.
各位、ご協力ありがとうございます。
「Virtual_Com_App」 で 送信処理を実施したときに、11回送信後、Hard Fault する現象に関して、解決しましたので報告します。
以下のモジュールによる送信後に、送信するために獲得したバッファの解放がされていない事が原因でした。
< モジュール名:usb_status usb_dci_khci_send() >
└> ここの出口で解放処理を追加すると受信側の解放と重複して動作しませんでした。
バッファの数は「usb_dev_ptr->xd_entries」にエントリされていて、起動時(未接続)は「12」に設定されています。
その状態からターミナルに接続すると接続処理で 2個使用されて「10」に減少します。
そのため、「 /* User Code */ 」の位置に送信処理を追加すると、1回送信する毎に減少していき、
11回目には「0」となっているため、バッファが獲得できず、送信バッファのアドレスが「0」で返り、
上記で説明した箇所で アドレスへの「0」のアクセスにより Hard Fault していました。
「001」の構成で問題無く送信が継続できるのは、受信時にバッファを 1個解放処理を実施しているためです。
<修正案>
以下の修正案は、「Virtual_Com_App」の送信処理で使用したハンドラ「g_app_handle」を継承する
必要があったため、送信処理と同じように「Virtual_Com_App」からの呼び出しルートに従っています。
(左側の数字は行数です。)
----------------------------------------------------------------------------------------------------
・・・\KSDK_1.0.0\usb\example\device\cdc\virtual_com\
virtual_com.c
最初に提示した「002」の 「 /* User Code */ 」の箇所に以下の解放処理を入れる。
static uint32_t Send_Init_Message = 0; /* Global Area に置く */
void Virtual_Com_App(void)
{
/* User Code */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <ここから追加(002)> */
if ((CmdSendRequest == 1)&&(g_recv_size == 0)) {
uint8_t error;
uint8_t cmd_size;
CmdSendRequest = 0;
if ( Send_Init_Message != 0 ) {
usb_cdc_use_buffer_free(g_app_handle); /* ここで send buffer を解放する。*/
}
else {
Send_Init_Message = 1;
}
str_copy(cmd_send_buf, "Prompt> ");
cmd_size = 8;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <追加はここまで> */
if(g_recv_size)
{
int32_t i;
/* Copy Buffer to Send Buff */
for (i = 0; i < g_recv_size; i++)
{
//printf("Copied: %c\n", g_curr_recv_buf[i]);
g_curr_send_buf[g_send_size++] = g_curr_recv_buf[i];
}
g_recv_size = 0;
CmdSendRequest = 1; /* - - - - - - - - - - - - - - - - - - <ここを追加> */
}
:
:
----------------------------------------------------------------------------------------------------
・・・\KSDK_1.0.0\usb\usb_core\device\sources\classes\cdc\
usb_cdc.c
[以下を最後の「/* EOF */」の前に追加]
861 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* @name usb_cdc_use_buffer_free <external application call module>*/
/* @param None */
/* @return usb_status */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
usb_status usb_cdc_use_buffer_free(cdc_handle_t handle)
{
usb_status error = USB_OK;
cdc_device_struct_t * cdc_obj_ptr;
cdc_obj_ptr = (cdc_device_struct_t *)handle;
if (NULL == cdc_obj_ptr)
return USBERR_ERROR;
usb_class_use_buffer_free(cdc_obj_ptr->class_handle);
return error;
}
----------------------------------------------------------------------------------------------------
・・・\KSDK_1.0.0\usb\usb_core\device\sources\classes\common\
usb_class.c
[以下を最後の「/* EOF */」の前に追加]
394 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* @name usb_class_use_buffer_free <external application call module>*/
/* @param None */
/* @return usb_status */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
usb_status usb_class_use_buffer_free(class_handle_t handle)
{
usb_status error = USB_OK;
usb_class_object_struct_t* class_object_ptr = (usb_class_object_struct_t*)handle;
if (NULL == class_object_ptr)
return USBERR_ERROR;
usb_dev_use_buffer_free(class_object_ptr->controller_handle);
return error;
}
----------------------------------------------------------------------------------------------------
・・・\KSDK_1.0.0\usb\usb_core\device\sources\classes\common\
usb_class_cdc.h
[以下を最後の行に追加]
237 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* @name usb_class_use_buffer_free <external application call module>*/
/* @param None */
/* @return usb_status */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
usb_status usb_class_use_buffer_free(class_handle_t handle);
244 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* @name usb_cdc_use_buffer_free <external application call module> */
/* @param None */
/* @return usb_status */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
usb_status usb_cdc_use_buffer_free(cdc_handle_t handle);
/* * * * * * * < external application call module end > * * * * * */
----------------------------------------------------------------------------------------------------
・・・\KSDK_1.0.0\usb\usb_core\device\sources\controller\
usb_dev.c
[以下を最後の行に追加]
1585 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* @name usb_dev_use_buffer_free <external application call module>*/
/* @param None */
/* @return usb_status */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
usb_status usb_dev_use_buffer_free(usb_device_handle handle)
{
usb_status error = USB_OK;
// xd_struct_t* xd_ptr;
usb_dev_state_struct_t* usb_dev_ptr;
if (handle == NULL)
{
#if _DEBUG
printf("usb_device_send_data: handle is NULL\n");
#endif
return USBERR_ERROR;
}
usb_dev_ptr = (usb_dev_state_struct_t*)handle;
error = usb_khci_use_buffer_free(usb_dev_ptr->controller_handle);
return error;
}
----------------------------------------------------------------------------------------------------
・・・\KSDK_1.0.0\usb\usb_core\device\sources\controller\
usb_dev.h
[以下を最後の「/* EOF */」の前に追加]
160 /* * * * * * * * < external application call module > * * * * * * */
usb_status usb_dev_use_buffer_free(usb_device_handle handle);
/* * * * * * * < external application call module end > * * * * * */
----------------------------------------------------------------------------------------------------
・・・\KSDK_1.0.0\usb\usb_core\device\sources\controller\khci\
khci_dev.c
<Global Variablesの箇所>
143 static xd_struct_t* previous_xd_ptr;
< モジュール名:usb_status usb_dci_khci_send() >
1612 previous_xd_ptr = xd_ptr;
[以下を最後の行に追加]
2265 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* @name usb_khci_use_buffer_free <external application call module> */
/* @param None */
/* @return usb_status */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
usb_status usb_khci_use_buffer_free(usb_device_handle handle)
{
uint32_t i;
uint8_t ep_num;
usb_status error = USB_OK;
xd_struct_t* xd_ptr;
usb_khci_dev_state_struct_t* state_ptr = (usb_khci_dev_state_struct_t*)handle;
if (handle == NULL)
{
#if _DEBUG
printf("usb_device_send_data: handle is NULL\n");
#endif
return USBERR_ERROR;
}
xd_ptr = previous_xd_ptr;
usb_dci_khci_free_xd(state_ptr, xd_ptr);
return error;
}
----------------------------------------------------------------------------------------------------
・・・\KSDK_1.0.0\usb\usb_core\device\sources\controller\khci\
khci_dev.h
[以下を最後の行に追加]
76 /* * * * * * * * < external application call module > * * * * * * */
usb_status usb_khci_use_buffer_free(usb_device_handle handle);
/* * * * * * * < external application call module end > * * * * * */
----------------------------------------------------------------------------------------------------
また、virtual_com.c のタスク処理にて「vTaskDelay( )」を追加しました。
(無い場合タスク切替えが動作せず、正常に動作しない事が有りました。)
:
:
if((start_app==TRUE) && (start_transactions==TRUE))
{
Virtual_Com_App();
}
vTaskDelay( 10 ); // 10ms Task Delay <- ここに追加(時間は調整要)
:
:
----------------------------------------------------------------------------------------------------
─── 以上 ───
各位、ご協力ありがとうございます。
「Virtual_Com_App」 で 送信処理を実施したときに、11回送信後、Hard Fault する現象に関して、解決しましたので報告します。
以下のモジュールによる送信後に、送信するために獲得したバッファの解放がされていない事が原因でした。
< モジュール名:usb_status usb_dci_khci_send() >
└> ここの出口で解放処理を追加すると受信側の解放と重複して動作しませんでした。
バッファの数は「usb_dev_ptr->xd_entries」にエントリされていて、起動時(未接続)は「12」に設定されています。
その状態からターミナルに接続すると接続処理で 2個使用されて「10」に減少します。
そのため、「 /* User Code */ 」の位置に送信処理を追加すると、1回送信する毎に減少していき、
11回目には「0」となっているため、バッファが獲得できず、送信バッファのアドレスが「0」で返り、
上記で説明した箇所で アドレスへの「0」のアクセスにより Hard Fault していました。
「001」の構成で問題無く送信が継続できるのは、受信時にバッファを 1個解放処理を実施しているためです。
<修正案>
以下の修正案は、「Virtual_Com_App」の送信処理で使用したハンドラ「g_app_handle」を継承する
必要があったため、送信処理と同じように「Virtual_Com_App」からの呼び出しルートに従っています。
(左側の数字は行数です。)
----------------------------------------------------------------------------------------------------
・・・\KSDK_1.0.0\usb\example\device\cdc\virtual_com\
virtual_com.c
最初に提示した「002」の 「 /* User Code */ 」の箇所に以下の解放処理を入れる。
static uint32_t Send_Init_Message = 0; /* Global Area に置く */
void Virtual_Com_App(void)
{
/* User Code */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <ここから追加(002)> */
if ((CmdSendRequest == 1)&&(g_recv_size == 0)) {
uint8_t error;
uint8_t cmd_size;
CmdSendRequest = 0;
if ( Send_Init_Message != 0 ) {
usb_cdc_use_buffer_free(g_app_handle); /* ここで send buffer を解放する。*/
}
else {
Send_Init_Message = 1;
}
str_copy(cmd_send_buf, "Prompt> ");
cmd_size = 8;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <追加はここまで> */
if(g_recv_size)
{
int32_t i;
/* Copy Buffer to Send Buff */
for (i = 0; i < g_recv_size; i++)
{
//printf("Copied: %c\n", g_curr_recv_buf[i]);
g_curr_send_buf[g_send_size++] = g_curr_recv_buf[i];
}
g_recv_size = 0;
CmdSendRequest = 1; /* - - - - - - - - - - - - - - - - - - <ここを追加> */
}
:
:
----------------------------------------------------------------------------------------------------
・・・\KSDK_1.0.0\usb\usb_core\device\sources\classes\cdc\
usb_cdc.c
[以下を最後の「/* EOF */」の前に追加]
861 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* @name usb_cdc_use_buffer_free <external application call module>*/
/* @param None */
/* @return usb_status */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
usb_status usb_cdc_use_buffer_free(cdc_handle_t handle)
{
usb_status error = USB_OK;
cdc_device_struct_t * cdc_obj_ptr;
cdc_obj_ptr = (cdc_device_struct_t *)handle;
if (NULL == cdc_obj_ptr)
return USBERR_ERROR;
usb_class_use_buffer_free(cdc_obj_ptr->class_handle);
return error;
}
----------------------------------------------------------------------------------------------------
・・・\KSDK_1.0.0\usb\usb_core\device\sources\classes\common\
usb_class.c
[以下を最後の「/* EOF */」の前に追加]
394 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* @name usb_class_use_buffer_free <external application call module>*/
/* @param None */
/* @return usb_status */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
usb_status usb_class_use_buffer_free(class_handle_t handle)
{
usb_status error = USB_OK;
usb_class_object_struct_t* class_object_ptr = (usb_class_object_struct_t*)handle;
if (NULL == class_object_ptr)
return USBERR_ERROR;
usb_dev_use_buffer_free(class_object_ptr->controller_handle);
return error;
}
----------------------------------------------------------------------------------------------------
・・・\KSDK_1.0.0\usb\usb_core\device\sources\classes\common\
usb_class_cdc.h
[以下を最後の行に追加]
237 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* @name usb_class_use_buffer_free <external application call module>*/
/* @param None */
/* @return usb_status */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
usb_status usb_class_use_buffer_free(class_handle_t handle);
244 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* @name usb_cdc_use_buffer_free <external application call module> */
/* @param None */
/* @return usb_status */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
usb_status usb_cdc_use_buffer_free(cdc_handle_t handle);
/* * * * * * * < external application call module end > * * * * * */
----------------------------------------------------------------------------------------------------
・・・\KSDK_1.0.0\usb\usb_core\device\sources\controller\
usb_dev.c
[以下を最後の行に追加]
1585 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* @name usb_dev_use_buffer_free <external application call module>*/
/* @param None */
/* @return usb_status */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
usb_status usb_dev_use_buffer_free(usb_device_handle handle)
{
usb_status error = USB_OK;
// xd_struct_t* xd_ptr;
usb_dev_state_struct_t* usb_dev_ptr;
if (handle == NULL)
{
#if _DEBUG
printf("usb_device_send_data: handle is NULL\n");
#endif
return USBERR_ERROR;
}
usb_dev_ptr = (usb_dev_state_struct_t*)handle;
error = usb_khci_use_buffer_free(usb_dev_ptr->controller_handle);
return error;
}
----------------------------------------------------------------------------------------------------
・・・\KSDK_1.0.0\usb\usb_core\device\sources\controller\
usb_dev.h
[以下を最後の「/* EOF */」の前に追加]
160 /* * * * * * * * < external application call module > * * * * * * */
usb_status usb_dev_use_buffer_free(usb_device_handle handle);
/* * * * * * * < external application call module end > * * * * * */
----------------------------------------------------------------------------------------------------
・・・\KSDK_1.0.0\usb\usb_core\device\sources\controller\khci\
khci_dev.c
<Global Variablesの箇所>
143 static xd_struct_t* previous_xd_ptr;
< モジュール名:usb_status usb_dci_khci_send() >
1612 previous_xd_ptr = xd_ptr;
[以下を最後の行に追加]
2265 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* @name usb_khci_use_buffer_free <external application call module> */
/* @param None */
/* @return usb_status */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
usb_status usb_khci_use_buffer_free(usb_device_handle handle)
{
uint32_t i;
uint8_t ep_num;
usb_status error = USB_OK;
xd_struct_t* xd_ptr;
usb_khci_dev_state_struct_t* state_ptr = (usb_khci_dev_state_struct_t*)handle;
if (handle == NULL)
{
#if _DEBUG
printf("usb_device_send_data: handle is NULL\n");
#endif
return USBERR_ERROR;
}
xd_ptr = previous_xd_ptr;
usb_dci_khci_free_xd(state_ptr, xd_ptr);
return error;
}
----------------------------------------------------------------------------------------------------
・・・\KSDK_1.0.0\usb\usb_core\device\sources\controller\khci\
khci_dev.h
[以下を最後の行に追加]
76 /* * * * * * * * < external application call module > * * * * * * */
usb_status usb_khci_use_buffer_free(usb_device_handle handle);
/* * * * * * * < external application call module end > * * * * * */
----------------------------------------------------------------------------------------------------
また、virtual_com.c のタスク処理にて「vTaskDelay( )」を追加しました。
(無い場合タスク切替えが動作せず、正常に動作しない事が有りました。)
:
:
if((start_app==TRUE) && (start_transactions==TRUE))
{
Virtual_Com_App();
}
vTaskDelay( 10 ); // 10ms Task Delay <- ここに追加(時間は調整要)
:
:
----------------------------------------------------------------------------------------------------
─── 以上 ───
koumotoさん、ご協力ありがとうございます。
現在の調査状況を連絡します。
「usb_dev.c」の1103行目から呼び出される 「khci_dev.c」の「usb_status usb_dci_khci_get_xd (224行目)」
で、240行目で実行される if文で「usb_dev_ptr->xd_entries」をチェックしているが、正常時は「1」が返って
くるが、Enterを 11回目に実行したときに「0」が返ってきて「USBERR_DEVICE_BUSY」で戻って(return)います。
正常時の「1」が返って来た場合は、246行目の「*xd_ptr_ptr = usb_dev_ptr->xd_head;」を実行して、
「xd_struct_t」にアドレスを設定しますが、「0」が返ってきた場合には「xd_struct_t」にアドレスが
設定されません。 (このときには、usb_dev_ptr->xd_head にアドレスが設定されていません。)
「xd_struct_t」にアドレスが設定されない状態で「usb_dev.c」に戻って来たときに、「xd_struct_t」で
構造体宣言されている「xd_ptr」のアドレスポインタが(自環境の場合)「0x00000008」で書き換えられない
ままになり、1118行目の「xd_ptr->bdirection = USB_SEND;」の実行で「Hard_Fault」になっています。
ここで、1103行目で「error」がエラーとして返っていた場合に、1107行目からの「xd_ptr->」構造体への
アクセスはしないようにしなければいけません。
「virtual_com.c」の「Virtual_Com_App」で「g_curr_send_buf」への送信要求の位置が異なることで
なぜ Enterが 11回目実行された場合に「usb_dev_ptr->xd_entries」が「0」で返ってくるのかを
調べる必要が有ります。
---------------------------------------------------------------------------------------------
usb_dev.c
usb_status usb_device_send_data 1066 行目
(
/* [IN] the USB_USB_dev_initialize state structure */
usb_device_handle handle,
/* [IN] the Endpoint number */
uint8_t ep_num,
/* [IN] buffer to send */
uint8_t * buff_ptr,
/* [IN] length of the transfer */
uint32_t size
)
:
error = ((usb_dev_interface_functions_struct_t*)\ 1103 行目
usb_dev_ptr->usb_dev_interface)->dev_get_xd(usb_dev_ptr->controller_handle, &xd_ptr);
:
/* Initialize the new transfer descriptor */
xd_ptr->ep_num = ep_num;
xd_ptr->bdirection = USB_SEND; 1118 行目
---------------------------------------------------------------------------------------------
khci_dev.c
usb_status usb_dci_khci_get_xd 224 行目
(
usb_device_handle handle,
/* [IN] the dTD to enqueue */
xd_struct_t** xd_ptr_ptr
)
:
if (!usb_dev_ptr->xd_entries) 240 行目
{
OS_Unlock();
return USBERR_DEVICE_BUSY;
}
*xd_ptr_ptr = usb_dev_ptr->xd_head; 246 行目
if (usb_dev_ptr->xd_head)
:
---------------------------------------------------------------------------------------------
よろしくお願いします。
山崎さん、こんばんは。
当方でプログラムをビルドして実行しました。
再現しました。が、この状況はICEがないと追いきれないと思います。
しかし、11回目という回数は入力する文字に依存するようです。
Enterキーの場合は11回ですが、aとかですと5回以内に止まってしまいます。
if((CmdSendRequest == 1)&&(g_recv_size)) {
CmdSendRequest = 0;
str_copy(g_curr_send_buf, "Prompt> ");
g_send_size = 8;
}
であれば、HardFaultは発生しません。(001)と等価なので当たり前といえば当たり前ですが。
すみません、これでは意図違いである理由って何でしたっけ?
別のバッファからコピーしたいだけならg_recv_sizeを見るのもありかなと思います。
ただし、この場合、約1文字入力ごとに「Prompt> 」が表示されてしまいます。
(001)の場合も同様です。本来、こういう意図のプログラムなのでしょうか?
すみません、やりたかったことは、文字列をいれてCR+LFを入力した後に「Prompt> 」の表示なのでしょうか?
本来のプログラムが1文字以上の入力があればすぐさまVirtuel COMに文字を出力するものなのでCR+LFを待ち合わせるのは難しい気がします。
Yasuhiko Koumoto.
koumotoさん、確認ありがとうございます。
やりたい事は、
1. コマンド文字列を入力後に、結果を返して、最後にプロンプトを出力します。
(コマンド解析と結果の作成は別のタスクで実施します。)
2. 装置側でイベントが起こった時に、何が起こったかがわかるように自立的にイベント内容を出力します。
(イベント内容の作成は別のタスクで実施します。)
上記の 1はCR/LFの受信後なのでなんとかなりそうですが、2の自立的に出力をする事が難しそうです。
CR/LFの処理については、以下で対応出来そうです。
if (str_comp(g_curr_recv_buf, InCrLf) == 0) {
CmdSendRequest = 1;
}
/*----------------------------------------------------------------------*/
int str_comp(uint8_t dst_str[], uint8_t src_str[])
{
int i;
int n;
n = str_len(src_str);
for (i = 0; i < n; i++) {
if (dst_str[i] != src_str[i]) {
return (1);
}
}
return(0);
}
/*----------------------------------------------------------------------*/
[usb_dev.c]を以下のようにコードを追加する事で、「Hard_Fault」は回避できそうです。
1100 if (((usb_dev_interface_functions_struct_t*)\
1101 usb_dev_ptr->usb_dev_interface)->dev_get_xd != NULL)
1102 {
1103 error = ((usb_dev_interface_functions_struct_t*)\
1104 usb_dev_ptr->usb_dev_interface)->dev_get_xd(usb_dev_ptr->controller_handle, &xd_ptr);
1105
1106 /* エラーで返ってきた時に以下の「xd_ptr->」アクセスでベクトルテーブルにアクセスして Hard_Fault になるため
1107 エラーコードを付けて戻るようにする。 : 2015/02/17 by N.Y */
1108 #if 1
1109 if (error != USB_OK) {
1110 return error;
1111 }
1112 #endif
1113
1114 }
上記、1105行目~113行目まで追加しました。
これで「void Virtual_Com_App(void)」までエラーコードを伝えられます。
こちらの環境では、
異常になったときのエラーコードは、「USBERR_DEVICE_BUSY = 0xc1」が返って来ています。
このときに、「USB0_ERRSTAT」が「0x02」となり、「CRC5EOF」のビットが「1」となっています。
異常になったときに「USB0_ERRSTAT」で「CRC5EOF」のビットが「1」になっていないかの確認は可能でしょうか。
よろしくお願いします。
山崎さん、申し訳ないです。
当方ではどうしてもHardFaultを回避する方法を発見できませんでした。
おそらく、山崎さんがやりたいことは、最初の(001)に近い、次の処理しかないと思います。
これは、(002)での追加をすべて削除しています。
if(g_recv_size)
{
int32_t i;
/* Copy Buffer to Send Buff */
for (i = 0; i < g_recv_size; i++)
{
//printf("Copied: %c\n", g_curr_recv_buf[i]);
g_curr_send_buf[g_send_size++] = g_curr_recv_buf[i];
}
g_recv_size = 0;
#if 1
if (g_curr_recv_buf[g_recv_size]=='\r') {
for(i=0; i<8; i++){
g_curr_send_buf[g_send_size+i]="Prompt> "[i];
}
g_send_size+=8;
}
#endif
}
この記述ならばHardFaultは発生しませんし、Enterを押した直後に「Prompt> 」が表示されます。
それまでに入力された文字列(TOKEN?)はg_curr_recv_bufの中に入っていると思います。
すみません、もうこれ以上は、ギブアップです。
Yasuhiko Koumoto.
koumotoさん、ご協力ありがとうございます。
おかげさまで解決することが出来ました。
koumotoさん、ご協力ありがとうございます。
[usb_drv.c]で、送信側と同じような箇所が受信側にも有りました。
: :
1011 if (((usb_dev_interface_functions_struct_t*)\
1012 usb_dev_ptr->usb_dev_interface)->dev_get_xd != NULL)
1013 {
1014 error = ((usb_dev_interface_functions_struct_t*)\
1015 usb_dev_ptr->usb_dev_interface)->dev_get_xd(usb_dev_ptr->controller_handle, &xd_ptr);
追加 if (error != USB_OK) {
追加 return error;
追加 }
1016 }
: :
1027 /* Initialize the new transfer descriptor */
1028 xd_ptr->ep_num = ep_num;
1029 xd_ptr->bdirection = USB_RECV;
1030 xd_ptr->wtotallength = size;
1031 xd_ptr->wstartaddress = buff_ptr;
: :
koumotoさんの方では、TeraTermのボーレートが「115200」となっていますが、こちらでは「115200」
で安定しなかったため、安定する速度まで徐々に下げて「19200」で使用しています。
送信処理の挿入箇所により、(002)で特定の回数で USBがエラー(こちらでは「CRC5EOF」ですが。)
となってしまう所は、ドライバのどこかに問題があるのではないかと思います。
今は調査に時間が取れなくなったので、時間をみて調べてみます。
とりあえずは、受信処理の中で入力コマンドの処理が完了するまで待ち合わせして、Totalで64バイト
を超えないように応答を返していこうと考えています。
これでは自立メッセージが出せなくなりますが・・・・
よろしくお願いします。
山崎さん、当方ではusb_dev.cの修正でもHardFaultは発生するようです。
CRC5EOFの値も確認できませんでした。
申し訳ありません。
HardFaultが発生しない条件でいろいろ試行してみたのですが、以下が一番理想形に近いと思われます。
ただし、以下の設定だと、文字列を入力後、Enterを入れて、あと1文字入力(この文字は無視される)しないと「Prompt> 」が表示されません。
どうしたら回避できるか試しましたが、回避できませんでした。
if ((CmdSendRequest == 1)&&(g_recv_size!=0)) { CmdSendRequest=0;
str_copy(g_curr_send_buf, "Prompt> ");
g_send_size = 8; g_recv_size = 0; }
if(g_recv_size) { int32_t i; /* Copy Buffer to Send Buff */ for (i = 0; i < g_recv_size; i++) { //printf("Copied: %c\n", g_curr_recv_buf[i]); g_curr_send_buf[g_send_size++] = g_curr_recv_buf[i]; } g_recv_size = 0; if (g_curr_recv_buf[g_recv_size]=='\r') { CmdSendRequest = 1; } }
状況的には、g_recv_size=0のときに、g_curr_send_bufに値を入れるとHardFaultになるようです。
この場合は、g_send_size=0になるのを待ち合わせればいいのかもしれません。
すみません、時間がなかったので、今日はこんなところまでです。
ところで、main関数の最初の部分でdbg_uartの初期化があったので、printfがVirturl COMでない方の端末に表示できると思ったのですが、無理みたいですね。printfが使えれば、もっと細かい状況が得られると思うのですが。
Yasuhiko Koumoto.
こんにちは 山崎さん。
「prompt>」の表示がおかしいのは「\r\n」を転送してないからと思われます。この2文字の転送を止めた理由は何でしょうか。Hard Faultですが、理由はよくわかりません。ただ、(002)のケースではCmdSendRequestをvolatile宣言しないとコンパイラの最適化によって 「if (CmdSendRequest == 1) {」が正しく実行されない恐れがあります。
核心を突いたアドバイスはできませんが、助けになれば幸いです。
Yasuhiko Koumoto.
koumotoさん、アドバイスありがとうございます。
以下のように「volatile」宣言してみましたが、状況は変わりませんでした。
volatile static int CmdSendRequest;
コンパイラの最適化オプションは「なし」に設定しています。
また、002で「Prompt> 」に「\r\n」を付けていないのは、元々の「Virtual_Com_App」
が受信したデータを送信バッファ( g_curr_send_buf )に転送して、エコーバック処理
をしているためです。
PCで Enter押下
└> 受信した「\r\n」を送信バッファへ転送,
送信バイト数( g_send_size )を設定
└> 送信処理で「\r\n」を送信
└>User Code側で「Prompt> 」を送信
よろしくお願いします。
山崎さん、HardFaultの発生する箇所は特定されていたのですね。失礼しました。
(001)と(002)のコードを比べたとき、(002)ではg_send_sizeの値が常に意図通りになるのか心配です。
(002)において、
if (CmdSendRequest == 1) { … }
をif(g_recv_size){ }と if(g_send_size){ }の間に持ってきてもHardFaultは発生するのでしょうか?
この場合は(001)と等価だと思うのですが、いかがでしょう?
ところで、(001)にしても(002)にしても、if(g_recv_size){ }で更新されるg_send_sizeを転送が完了したかどうかわからないうちに(001)では10、(002)では8に書き換えていますが、これは大丈夫なのでしょうか?
推測が外れていたら無視してください。
Yasuhiko koumoto.
koumotoさん、アドバイスありがとうございます。
「g_send_size」については if(g_send_size){ }に入ったときに「g_send_size=0」
としているため、「10/8」への書き換えは問題は無いと思いますが、関数を追っていくと
「g_curr_send_buf」が ずっとポインタ渡しになっています。
そのため、
│Prompt> PrPrompt> PrPrompt>
~~-------
│ └> 「if (CmdSendRequest == 1) {}」で「g_curr_send_buf」に上書きした"Prompt> "
└> 「\r\n, size=2」(if(g_recv_size){ }で受信した「\r\n」)
※ 「\r\n」の送信処理前に「g_curr_send_buf」が"Prompt> "に書き換えられている。
となっていて、送信バッファの競合が起こって「HardFault」になっているのではと思います。
ただ、「Enter」を押下する回数が固定なのが気になりますが。
送信完了がわかるフラグがあれば回避できるかもしれません。
スタック使用量については「1%」に満たないため、スタックオーバーフローは起こっていません
よろしくお願いします。
山崎さん、こんにちは。
少なくとも、g_send_sizeが0でないときに、g_curr_send_bufの内容を変更するのはまずい気がします。
「Prompt>」をg_curr_send_bufに転送するのをg_send_size=0のときに限定してはいかがでしょうか?
私はUSBには詳しくないのですが、確実に転送完了を見るためには、USB0_ISTATの(4007_2080h)のTOKDNE(ビット3)を観測してみてはどうでしょうか?
あまり、助けになれなくて申し訳ありません。
Yasuhiko Koumoto.
koumotoさん、アドバイスありがとうございます。
「USB0_ISTAT」は割込みステータスで割込み処理の箇所でステータスをクリアするため、
「Virtual_Com_App」では条件が捉えられませんでした。
代わりに、
uint32_t i = 0x800000;
if (CmdSendRequest == 1) {
CmdSendRequest = 0;
while(i) {
i--;
}
str_copy(g_curr_send_buf, "Prompt> ");
g_send_size = 8;
}
でウエイトさせてみましたが、「11回目」のEnterで Hard_Faultしてしまいました。(最初と状況は同じです。)
┌──────────────────
│<┘(1)
│Prompt> <┘(2) <= Enter入力後約0.5秒後に表示
│Prompt> <┘(3)
│Prompt> <┘(4)
│Prompt> <┘(5)
│Prompt> <┘(6)
│Prompt> <┘(7)
│Prompt> <┘(8)
│Prompt> <┘(9)
│Prompt> <┘(10)
│Prompt> <┘(11)
│_ <= カーソル位置
│
どうも、バッファ競合ではなさそうです。
よろしくお願いします。
山崎さん
やはり、g_send_sizeやg_recv_sizeを無視してg_curr_send_bufを書きつぶしているのが悪い気がします。
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <ここから追加> */
static int CmdSendRequest;
if (CmdSendRequest == 1) { CmdSendRequest = 0; str_copy(g_curr_send_buf, "Prompt> "); g_send_size = 8; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <追加はここまで> */
if(g_recv_size) { int32_t i; /* Copy Buffer to Send Buff */ for (i = 0; i < g_recv_size; i++) { //printf("Copied: %c\n", g_curr_recv_buf[i]); g_curr_send_buf[g_send_size++] = g_curr_recv_buf[i]; } g_recv_size = 0; CmdSendRequest = 1; /* - - - - - - - - - - - - - - - <ここを追加> */ }
の部分を
if(g_recv_size)
{
int32_t i;
/* Copy Buffer to Send Buff */
for (i = 0; i < g_recv_size; i++)
{
//printf("Copied: %c\n", g_curr_recv_buf[i]);
g_curr_send_buf[g_send_size++] = g_curr_recv_buf[i];
}
for (i=0; i<8 ; i++)
{
g_curr_send_buf[g_send_size++] = "Prompt> "[i];
}
g_recv_size = 0;
}
else
{
str_copy(g_curr_send_buf, "Prompt> ");
g_send_size = 8;
}
としたら、どうでしょうか?これなら修正前とアルゴリズムに変化がないと思います。
Yasuhiko Koumoto.
koumotoさん、アドバイスありがとうございます。
上記コードではTeraTermが接続された時点で以下のように"Prompt> "が表示されて
「Hard_Fault」で止まってしまいます。(停止場所等は最初の状況と同じです。)
┌────────────────────────────
│
│Prompt> Prompt> Prompt> Prompt> Prompt> Prompt> Prompt>
│
「str_copy(g_curr_send_buf, "Prompt> ");」を
「for ~ {
g_curr_send_buf[g_send_size++] = "Prompt> "[i];
} 」に替えてみましたが、
状況は変わりませんでした。
「g_send_size」については if(g_send_size){ } に入ったときに
uint8_t size = g_send_size;
g_send_size=0;
と「0」に書き換えていて、「USB_Class_CDC_Send_Data(... );」では「size」は
ポインタではなく数値渡しとなっています。
よろしくお願いします。
山崎さん、そうですか。追加したelse以降のstr_copyのせいで「Prompt > 」が出続けるのですね。
else以降を削除した場合、状況に変化はありますでしょうか?
少なくとも、最初から「Prompt> 」が出ることはなくなると思います。
たびたび、すみません。
Yasuhiko Koumoto.
koumotoさん、アドバイスありがとうございます。
elseの箇所を削除した場合は、「001」のパターンと同じになり、「001」の結果通り
正常に出力されます。
この場合は、応答がエコーバック的な応答となり、別タスクで作成した出力したい
メッセージが出力出来なくなります。
(本来は「if (CmdSendRequest == 1) { ... }」で別に設定されたバッファから
メーセージのコピー処理をしたいです。)
また、KSDK_1.1.0 で改善されていないかを確認をするため、インストールして
最初に記載した通りの手順で起動させましたが、PC側で USB-Serialのポート
(実際には COM ポート)が認識できず、デバイスマネージャで不明デバイスに
なってしまい、COMポートに接続出来ませんでした。
よろしくお願いします。
山崎さん
すみません、意図が理解できていませんでした。
それならば(002)に戻って
volatile static int CmdSendRequest=0;
if ((CmdSendRequest == 1)&&(g_recv_size==0)&&(g_send_size==0)) { CmdSendRequest = 0; str_copy(g_curr_send_buf, "Prompt> "); g_send_size = 8; }
ではいかがでしょうか?
山崎さんの環境がFRDM-K64Fだとさっき気づいたのでこちらでも試してみようと思いましたが、Virtual COM用のmicroBのUSBケーブルがありませんでした。明日、買ってきます。ソフトウェアのコンパイルまでは済んでいます。
Yasuhiko Koumoto.
koumotoさん、対応ありがとうございます。
以下のような構成です。
PC ボード (CPU:MK64FN1M0VLQ12)
┌────┐ ICE ┌────────────┐
│ ┌┐│ USBケーブル ┌─┐ │┌┐ │
│ ││├──────────┤ ├───┤│ │JTAG │
│ └┘│ └─┘ │└┘ │
│ ┌┐│ USBケーブル │┌─┐ │
│ ││├────────────────┤│ │USB │
│ └┘│(virtual com で使用) │└─┘ │
└───│┘ └─│──────────┘
│ │
↓コネクタ形状 ↓コネクタ形状
┌──────┐ _
│==== │ / \
└──────┘ │ ロ ロ │
└────┘
以下のように送信バッファの領域を替えてみましたが、結果は変わりませんでした。
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <ここから追加> */
int str_copy(uint8_t dst_str[], uint8_t src_str[]);
int strlen(uint8_t char_count[]);
static uint8_t cmd_send_buf[DATA_BUFF_SIZE];
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <追加はここまで> */
void Virtual_Com_App(void)
{
/* User Code */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <ここから追加(002)> */
volatile static int CmdSendRequest;
volatile static int CmdPromptRequest;
if (CmdSendRequest == 1) {
uint8_t error;
uint8_t cmd_size;
CmdSendRequest = 0;
OSA_TimeDelay(100); //delay 100ms
str_copy(cmd_send_buf, "Prompt> ");
cmd_size = 8;
error = USB_Class_CDC_Send_Data(g_app_handle, DIC_BULK_IN_ENDPOINT,
cmd_send_buf, cmd_size); <------------------------- バッファ領域を替えてみました。
if(error != USB_OK)
{
/* Failure to send Data Handling code here */
}
OSA_TimeDelay(100); //delay 100ms
}
:
:
よろしくお願いします。