LPC1343 USB Virtual COMをカスタマイズ!
出来た事
1.LPC1343でUSB Virtual COMのExample pjtをモディファイしてカスタマイズ
開発Listへ戻る
前回、Example codeをそのままコンパイルしてUSBシリアル変換を実現しましたが
はっきり言って単なるUSBシリアル変換ならFT232RLを買えばいいんですよ。
そんなモンをLPC1343で作ってもまったく意味がない。(と感じてる)
USBを使ってコマンド転送(設定変更などの指示)とか、内部処理結果などのデータ取得が出来れば
おおっ!!結構やるね!みたいになります(私の周りではですが・・・)
今回、NXPのサンプルコードを眺めていたら結構簡単に出来そうな感じでした!
(ポジティブ(^^)/)
まず、Example codeをみてみます。USB-シリアル変換機能を実現するExample pjtのコードです。
見てみるといっても概略です。詳細はぜんぜんわかっていません。
インポートしたusbcdcのpjt内のsrcフォルダ内のvcomdemo.cを見ます。
(インポートの仕方などは前回のエントリ参照)
vcomdemo.c
まずmain関数
int main (void) {
/* Enable Timer32_1, IOCON, and USB blocks */
LPC_SYSCON->SYSAHBCLKCTRL |= (EN_TIMER32_1 | EN_IOCON | EN_USBREG);USBIOClkConfig();
VCOM_Init(); // VCOM Initialization
USB_Init(); // USB Initialization
USB_Connect(TRUE); // USB Connectwhile (!USB_Configuration) ; // wait until USB is configured
while (1) { // Loop forever
VCOM_Serial2Usb();
VCOM_CheckSerialState();
VCOM_Usb2Serial();
} // end while
} // end main ()
大事なところは青字のところです。
まぁ記載を見ると大体意味がわかるんですが。。。
1.VCOM_Serial2USB()は シリアルデータ(UART Rx受信データ)をUSBに変換してLPC1343からPCに送信します。
2.VCOM_CheckSerialState() こいつはステータスなんでしょうが、削除するとPCがLPC1343をVirtual COMとして
認識できなくなりました。盲目に入れておきましょう。
3.VCOM_Usb2Serial()はPCからUSBで送信されてきたデータをシリアルに変換してUARTのTxとして出力します。
3については、USB受信データをそのまま利用出来れば良いです。シリアルはいりません。
1はUARTの受信データではなく内部信号をUSBで送信できれば良いわけです。
つまり、1,3からシリアル部分を切り離すことが出来ればいいのです。
VCOM_Serial2USB
void VCOM_Serial2Usb(void) {
static char serBuf [USB_CDC_BUFSIZE];
int numBytesRead, numAvailByte;
ser_AvailChar (&numAvailByte); //UART RXのバッファ確認
if (numAvailByte > 0) { // UART Rxのバッファになんか入ってる?
if (CDC_DepInEmpty) { // USBの送信処理終わってる?
numBytesRead = ser_Read (&serBuf[0], &numAvailByte); //UART Rxのバッファに入ってるもを移動+有効byte数も取り出す。CDC_DepInEmpty = 0; // USBをBusyにする
USB_WriteEP (CDC_DEP_IN, (unsigned char *)&serBuf[0], numBytesRead); //USBで有効Byte数のデータを送信する。
}
}
}
コメントの説明で大体わかるかと思いますが。
UARTの受信部分はデータを溜め込んでいます。
それを numBytesRead = ser_Read (&serBuf[0], &numAvailByte); で取り出しています。
USBの送信も時間がかかるので、USB送信中に入力されたUART Rxの信号をロストしないように
別のバッファを持っているということでしょう。
シリアル部分は要りませんので送信データと有効Byte数を独自で作成できれば良いようです。
(上記関数内でのserBuf とnumBytesReadをカスタマイズする)
VCOM_Usb2Serial
void VCOM_Usb2Serial(void) {
static char serBuf [32];
int numBytesToRead, numBytesRead, numAvailByte;CDC_OutBufAvailChar (&numAvailByte); //USBから受けたデータのバッファ確認
if (numAvailByte > 0) { //USBから有効なデータを受けている?
numBytesToRead = numAvailByte > 32 ? 32 : numAvailByte;
numBytesRead = CDC_RdOutBuf (&serBuf[0], &numBytesToRead); //バッファの内容移動 + 有効byte数取り出し
ser_Write (&serBuf[0], &numBytesRead); //Uartで送信する。
}
}
似たような感じです。
USBで受信したデータを一度バッファに溜め込んで
別のバッファに移し、移したデータをUARTで送信しています。
こちらもUARTで送信中にUSBに新たなデータが入力された場合にデータロストしないように
バッファがあります。
ココでは結構簡単で、ser_Writeがまったく不要です。
numBytesRead = CDC_RdOutBuf (&serBuf[0], &numBytesToRead);後の
serBufが読み込んだ値、numByteReadが有効byte数ですから取り出せればOKです。
モディファイ内容
キーボードで's'と入力したら40桁の数字を帰ってくるようにする。
USB Virtual COM経由
Teratermで確認
まず VCOM_Usb2Serialです。
char VCOM_Usb2Serial(void) {
static char serBuf [32];
int numBytesToRead, numBytesRead, numAvailByte;CDC_OutBufAvailChar (&numAvailByte);
if (numAvailByte > 0) {
numBytesToRead = numAvailByte > 32 ? 32 : numAvailByte;
numBytesRead = CDC_RdOutBuf (&serBuf[0], &numBytesToRead);
// ser_Write (&serBuf[0], &numBytesRead);
return(serBuf[0]); // 1文字だけ返す
}
}
キーボードの入力は人力なので非常に遅いです。
バッファに2byteもたまることは無いでしょう。
今回は1文字 1byteのみ検出するようにしました。
シリアルでの送信関数を削除し、関数の結果として1文字だけ返すようにしました。
次にVCOM_Serial2Usbです。
void VCOM_Serial2Usb(char in_char) {
// static char serBuf [USB_CDC_BUFSIZE];
// int numBytesRead, numAvailByte;
char test[USB_CDC_BUFSIZE]="1234567890123456789012345678901234567890"; //送信データ作成
// ser_AvailChar (&numAvailByte);
// if (numAvailByte > 0) { // serial buffer has some data.
if(in_char=='s'){ // USBで's'が入力されたら
if (CDC_DepInEmpty) { // 1 is empty so if empty
// numBytesRead = ser_Read (&serBuf[0], &numAvailByte);
CDC_DepInEmpty = 0;
// USB_WriteEP (CDC_DEP_IN, (unsigned char *)&serBuf[0], numBytesRead);
USB_WriteEP (CDC_DEP_IN, (unsigned char *)&test[0], 40); //作成した40桁の数値を送信
}
}
}
シリアル部分は要りませんので削除
USBで's'が入力されたら、独自で作成した40桁の数値をUSBで送信。
(なので、1文字 char 入力としています)
最後にmain関数です。
int main (void) {
/* Enable Timer32_1, IOCON, and USB blocks */
char test='0';LPC_SYSCON->SYSAHBCLKCTRL |= (EN_TIMER32_1 | EN_IOCON | EN_USBREG);
USBIOClkConfig();
VCOM_Init(); // VCOM Initialization
USB_Init(); // USB Initialization
USB_Connect(TRUE); // USB Connectwhile (!USB_Configuration) ; // wait until USB is configured
while (1) { // Loop forever
VCOM_Serial2Usb(test); // read serial port and initiate USB event
VCOM_CheckSerialState();
test=VCOM_Usb2Serial();
}
}
新しく関数間でcharの受け渡しがあるのでtestという変数で受け渡しを実現しています。
この変更後、Teratermでsを入力するとちゃんと期待した40桁の数値が表示されました。
ちなみにBaudrateの設定は関係ありません。
USB部分にBaudrateの概念が無いからです。
また以下にコピペすれば今回の機能が実現するコードを置いておきます。
vcomdemo.c全部をコピペで入れ替え
#include "LPC13xx.h"
#include "type.h"#include "usb.h"
#include "usbcfg.h"
#include "usbhw.h"
#include "usbcore.h"
#include "cdc.h"
#include "cdcuser.h"
#include "serial.h"
#include "vcomdemo.h"
#include#define EN_TIMER32_1 (1<<10)
#define EN_IOCON (1<<16)
#define EN_USBREG (1<<14)/*----------------------------------------------------------------------------
Initializes the VCOM port.
Call this function before using VCOM_putchar or VCOM_getchar
*---------------------------------------------------------------------------*/
void VCOM_Init(void) {CDC_Init ();
}
/*----------------------------------------------------------------------------
Reads character from serial port buffer and writes to USB buffer
*---------------------------------------------------------------------------*/
void VCOM_Serial2Usb(char in_char) {
// static char serBuf [USB_CDC_BUFSIZE];
// int numBytesRead, numAvailByte;
char test[USB_CDC_BUFSIZE]="1234567890123456789012345678901234567890";
// ser_AvailChar (&numAvailByte);
// if (numAvailByte > 0) { // serial buffer has some data.
if(in_char=='s'){
if (CDC_DepInEmpty) { // 1 is empty so if empty
// numBytesRead = ser_Read (&serBuf[0], &numAvailByte);
CDC_DepInEmpty = 0;
// USB_WriteEP (CDC_DEP_IN, (unsigned char *)&serBuf[0], numBytesRead);
USB_WriteEP (CDC_DEP_IN, (unsigned char *)&test[0], 40);
}
}
}/*----------------------------------------------------------------------------
Reads character from USB buffer and writes to serial port buffer
*---------------------------------------------------------------------------*/
char VCOM_Usb2Serial(void) {
static char serBuf [32];
int numBytesToRead, numBytesRead, numAvailByte;CDC_OutBufAvailChar (&numAvailByte);
if (numAvailByte > 0) {
numBytesToRead = numAvailByte > 32 ? 32 : numAvailByte;
numBytesRead = CDC_RdOutBuf (&serBuf[0], &numBytesToRead);
// ser_Write (&serBuf[0], &numBytesRead);
return(serBuf[0]);
}
}/*----------------------------------------------------------------------------
checks the serial state and initiates notification
*---------------------------------------------------------------------------*/
void VCOM_CheckSerialState (void) {
unsigned short temp;
static unsigned short serialState;temp = CDC_GetSerialState();
if (serialState != temp) {
serialState = temp;
CDC_NotificationIn(); // send SERIAL_STATE notification
}
}/*----------------------------------------------------------------------------
Main Program
*---------------------------------------------------------------------------*/
int main (void) {
/* Enable Timer32_1, IOCON, and USB blocks */
char test='0';LPC_SYSCON->SYSAHBCLKCTRL |= (EN_TIMER32_1 | EN_IOCON | EN_USBREG);
USBIOClkConfig();
VCOM_Init(); // VCOM Initialization
USB_Init(); // USB Initialization
USB_Connect(TRUE); // USB Connectwhile (!USB_Configuration) ; // wait until USB is configured
while (1) { // Loop forever
VCOM_Serial2Usb(test); // read serial port and initiate USB event
VCOM_CheckSerialState();
test=VCOM_Usb2Serial();
} // end while
} // end main ()