PIC18F14K50のEUSARTで自動baudレート検出を行ってみます。
使用するのは、秋月通商のPIC18F14K50使用USB対応超小型マイコンボードです。
上記のボードに「PIC16F1827とPIC18F14K50のUSART接続」のところで紹介しました「Device-CDC-SerialEmulator」のソフトが入っています。
試験では、上記のボードのTXとRXを直接接続して(実機にはレベル変換のトランジスタが入っていますが5Vで動作させるのでトランジスタは無くても大丈夫です)TeraTermで接続し、キーボードから入力した文字がそのまま表示されることを確認します。
現在の設定
EUSART関連の設定をメモしておきます。(関係無いところもあるかも)
CONFIGURATION
CPUDIV = NOCLKDIV システムクロックを分周しない
USBDIV = OFF プライマリオシレータから直接USBクロックを受け取る
FOSC = IRC 内部RCオシレータ
PLLEN = ON 4xPLLオン
InitializeSystem
ADCON1 |= 0x0F;
InitializeUSART
unsigned char c;
ANSELH = 0;
OSCCON = 0b01110000; //内部クロック16MHz
UART_TRISRx = 1;
UART_TRISTx = 0;
RCSTA = 0b10010000; //Single Character RX
SPEN=1,RX9=0,SREN=0,CREN=1,ADDEN=0,FERR=0,OERR=0,RX9D=0
TXSTA = 0b00100100; //TX enable BRGH = 1
CSRC=0,TX9=0,TXEN=1,SYNC=0,SENDB=0,BRGH=1,TRMT=0,TX9D=0
BAUDCON = 0x08; //BRG16 = 1
ABDOVF=0,RCIDL=0,DTRXP=0,CKTXP=0,BRG16=1,-,WUE=0,ABDEN=0
SPBRGH = 1; //64MHz 57600baud H8-3069に合わせて57600baudに変更しています。
SPBRG = 21;
c = RCREG; //読み込み
オシレータモジュールのデータシートを見ていると64MHz?と考えられるようになってきました。
上の計算で57600baudでTeraTermの読み書きが出来たのが不思議ですが…
で、PIC18F14K50では、USBをフルスピード48MHzで動作させるための内部オシレータがない!
しかも、内部オシレータの最高周波数は32MHzまで。
ん?でも、私の手元にあるのはPIC18F14K50単品ではなく、PIC18F14K50使用USBマイコンボード。
ここでボードの説明書を見て納得
秋月のPIC18F14K50使用USB対応超小型マイコンボードにはOSC1に12MHzのクリスタルが接続されていました。
(気付くのが遅い 前、回路を組んだ時に気付けよ 私)
ということで、システムクロックを
FOSC=HS
4xPLLオン
CPUDIV<1:0>=00
で48MHzにします。
EUSART非同期モードのbaudレート表を見てみると
SYNC=0 TXSTAのbit4
BRGH=0 TXSTAのbit2
BRG16=1 BAUDCONのbit3
で300baud~115.2kbaudまで対応出来そうです。(この考え方間違ってないかな?)
取り敢えず、57.6kbaudで試してみます。
SPBRGH:SPBRG=51(10進)
MPLAB X IDEで「Clean and Build Main Project」実行
ボードを書き込みモードにして「USB Bootloader」を起動
上で作成したhexファイルを流し込みます。
ボードを実行モードに戻してUSBを接続
TeraTermを起動してボーレートを57600に設定
何かキーボード入力してみる。
次に、TeraTermのボーレートを115200に変更
何か入力してみる。
あら不思議。どちらもきちんと表示されました。
結局、110~921600まで全てきちんと表示されました。
ということで、main.cのプログラムを確認
「Device-CDC-SerialEmulator」には自動baudレート検出プログラムが入っていました。
/******************************************************************************
* Function: void mySetLineCodingHandler(void)
*
* PreCondition: USB_CDC_SET_LINE_CODING_HANDLER is defined
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: This function gets called when a SetLineCoding command
* is sent on the bus. This function will evaluate the request
* and determine if the application should update the baudrate
* or not.
*
* Note:
*
*****************************************************************************/
#if defined(USB_CDC_SET_LINE_CODING_HANDLER)
void mySetLineCodingHandler(void)
{
//If the request is not in a valid range
if(cdc_notice.GetLineCoding.dwDTERate.Val > 115200)
{
//NOTE: There are two ways that an unsupported baud rate could be
//handled. The first is just to ignore the request and don't change
//the values. That is what is currently implemented in this function.
//The second possible method is to stall the STATUS stage of the request.
//STALLing the STATUS stage will cause an exception to be thrown in the
//requesting application. Some programs, like HyperTerminal, handle the
//exception properly and give a pop-up box indicating that the request
//settings are not valid. Any application that does not handle the
//exception correctly will likely crash when this requiest fails. For
//the sake of example the code required to STALL the status stage of the
//request is provided below. It has been left out so that this demo
//does not cause applications without the required exception handling
//to crash.
//---------------------------------------
//USBStallEndpoint(0,1);
}
else
{
//Update the baudrate info in the CDC driver
CDCSetBaudRate(cdc_notice.GetLineCoding.dwDTERate.Val);
//Update the baudrate of the UART
#if defined(__18CXX) || defined(__XC8)
{
DWORD_VAL dwBaud;
dwBaud.Val = (DWORD)(GetSystemClock()/4)/line_coding.dwDTERate.Val-1;
SPBRG = dwBaud.v[0];
SPBRGH = dwBaud.v[1];
}
}
}
#endif
mySetLineCodingHandler(void)という関数でSPBRGとSPBRGHの値を書き換えているようです。
mySetLineCodingHandlerという関数はUSB_CDC_SET_LINE_CODING_HANDLERが有効なときに実行可能になるようです。
そして、USB_CDC_SET_LINE_CODING_HANDLERはusb_config.hにありました!
では、mySetLineCodingHandlerの呼び出し元はどこか。main.cにはありませんでした。
Overviewによると、バスにSetLineCodingコマンドが送られたら実行されるとか。
usb_config.hがインクルードされると自動ボーレート変換が標準で付いてくるという認識で良いのかな?
115200baudより高い周波数には対応してないのかな?
必要に迫られたらもっと深く掘り下げます。 汗