3 * Toyohashi Open Platform for Embedded Real-Time Systems/
4 * Advanced Standard Profile Kernel
6 * Copyright (C) 2007 by Embedded and Real-Time Systems Laboratory
7 * Graduate School of Information Science, Nagoya Univ., JAPAN
8 * Copyright (C) 2010 by TOPPERS/ASP for LPC project
9 * http://sourceforge.jp/projects/toppersasp4lpc/
12 * 上記著作権者は,以下の(1)〜(4)の条件を満たす場合に限り,本ソフトウェ
13 * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
14 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
15 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
16 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
18 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
19 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
20 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
22 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
23 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
25 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
26 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
27 * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
29 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
30 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
31 * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
32 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
35 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
36 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
37 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
38 * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
44 * \ingroup TOPPERS_SIO
45 * \brief ターゲット依存のシリアル・ペリフェラル制御ルーチン群
47 * ターゲット依存のシリアル・ペリフェラル制御ルーチン群。TOPPERS/ASPのシリアル
48 * ・タスクの下請けとして働く。詳細に関してはporting.txtを参照のこと。
59 #include "target_syssvc.h"
65 * \brief SIOPCBのインデックスからポートID番号への変換
67 * TOPPERS/ASPのSIOポートID番号は1オリジンだが、 siopcb_table[]は
68 * 0オリジンである。そのため、変換関数を使って与えられたインデックス番号から
72 #define INDEX2SIOPID(x) ((x) + 1)
74 * \brief ポート番号からSIOPCBのインデックスへの変換
76 * TOPPERS/ASPのSIOポートID番号は1オリジンだが、 siopcb_table[]は
77 * 0オリジンである。そのため、変換関数を使って与えられたポートID番号から
78 * PCBを取得するためのインデックスを作り出す。
80 #define SIOPID2INDEX(x) ((x) - 1)
82 * \brief ポートID番号からSIOPCBを取得する
84 * ポートID番号を元に、SIOPCBへのポインタを取得する。
86 #define GET_SIOPCB(x) (&siopcb_table[SIOPID2INDEX(x)])
90 * \brief ペリフェラル・レジスタの間隔
92 * ペリフェラルレジスタが何バイトごとに現れるかを記述する。この
95 #if defined(TOPPERS_CHIP_LPC17XX) | defined(TOPPERS_CHIP_LPC18XX)
96 #define UART_BOUNDARY 4
98 #error "You must define UART_BOUNDARY for your architecture"
101 * \brief 8250, 16450, 16550各レジスタのアドレス・オフセット。
104 * システムごとに異なるのでUART_BOUNDARYによってレジスタの配置境界を指定する。
105 * たとえばすべてのレジスタが8ビット境界で配置されているなら、UART_BOUNDARYは1,
106 * 16bit境界なら2, 32ビット境界なら4を指定する。
107 * UART_BOUNDARYはsys_config.hで定義する。
110 #define UART_RBR (0x00 * UART_BOUNDARY) /* 受信バッファレジスタ */
111 #define UART_THR (0x00 * UART_BOUNDARY) /* 送信データ・ホールド・レジスタ */
112 #define UART_DLL (0x00 * UART_BOUNDARY) /* 分周レジスタ下位バイト */
113 #define UART_IER (0x01 * UART_BOUNDARY) /* 割込みイネーブルレジスタ */
114 #define UART_DLM (0x01 * UART_BOUNDARY) /* 分周レジスタ上位バイト */
115 #define UART_IIR (0x02 * UART_BOUNDARY) /* 割込み識別レジスタ */
116 #define UART_FCR (0x02 * UART_BOUNDARY) /* FIFO制御レジスタ */
117 #define UART_LCR (0x03 * UART_BOUNDARY) /* ライン制御レジスタ */
118 #define UART_MCR (0x04 * UART_BOUNDARY) /* モデム制御レジスタ */
119 #define UART_LSR (0x05 * UART_BOUNDARY) /* ライン・ステータス・レジスタ */
120 #define UART_MSR (0x06 * UART_BOUNDARY) /* モデム・ステータス・レジスタ */
121 #define UART_SCR (0x07 * UART_BOUNDARY) /* スクラッチ・パッド・レジスタ */
122 #define UART_GCTL (0x09 * UART_BOUNDARY) /* Blackfinのみ。グローバル制御レジスタ */
124 #define ISR_TX 0x02 /* 送信割り込み発生 */
125 #define IER_TX 0x02 /* 送信割り込み許可 */
126 #define ISR_RX 0x01 /* 受信割り込み発生 */
127 #define IER_RX 0x01 /* 受信割り込み許可 */
129 #define LCR_DLAB 0x80 /* Divisor Enable */
130 #define LCR_NP_8_1 0x03 /* 8bit,1stop,Noparity,No break */
131 #define FCR_FIFO_DISABLE 0x00
133 #define LSR_RX_DATA_READY 0x01
134 #define LSR_TX_EMPTY 0x20
136 #define MCR_INT_ENABLE 0x08
139 #define DLM(divisor) (divisor/256)
140 #define DLL(divisor) (divisor%256)
144 * \brief シリアルI/Oポート管理ブロックエリア
146 SIOPCB siopcb_table[TNUM_PORT];
149 * \brief 各シリアル・ペリフェラルのレジスタのベースアドレス。
151 * この変数は初期化関数 sio_initialize()の中で参照され、
152 * レジスタアドレスは siopcb_table[]のしかるべきメンバー変数に
156 #ifdef TOPPERS_CHIP_LPC17XX
157 static const uint32_t sioreg_table[TNUM_PORT] = {
170 #elif defined(TOPPERS_CHIP_LPC18XX)
172 static const uint32_t sioreg_table[TNUM_PORT] = {
185 #error "You must define sioreg_table[]"
189 * \ingroup SIOSUPPORT
190 * \brief シリアルポート・ペリフェラル書き込み関数
191 * \param addr UARTペリフェラルのベースアドレス。通常はTHRのアドレスである。
192 * \param offset ベースアドレスに対する、オフセット値。単位はバイト。
193 * \param val レジスタに書き込む値。
195 * ベースアドレスとオフセットを整数で受け取り、ペリフェラルレジスタに
199 uart_write(uint32_t addr, uint32_t offset, uint8_t val)
201 #if defined(TOPPERS_CHIP_LPC17XX) | defined(TOPPERS_CHIP_LPC18XX)
202 sil_wrb_mem((void *)(addr + offset),val);
204 #error "You must define access method for your architecture"
209 * \ingroup SIOSUPPORT
210 * \brief シリアルポート・ペリフェラル読み込み関数
211 * \param addr UARTペリフェラルのベースアドレス。通常はTHRのアドレスである。
212 * \param offset ベースアドレスに対する、オフセット値。単位はバイト。
213 * \return レジスタから読み込んだ値。
215 * ベースアドレスとオフセットを整数で受け取り、ペリフェラルレジスタに
219 uart_read(uint32_t addr, uint32_t offset)
221 #if defined(TOPPERS_CHIP_LPC17XX) | defined(TOPPERS_CHIP_LPC18XX)
222 return(sil_reb_mem((void *)(addr + offset)));
224 #error "You must define access method for your architecture"
229 * \ingroup TOPPERS_SIO
230 * \defgroup SIOAPI シリアル・サービス・タスク用API
232 * シリアル・サービス・タスクから呼び出される関数群。シリアル・サービス・タスクはこれらの
233 * 関数を使ってペリフェラルを制御する。詳細はporting.txtの8.3節を参照。
239 * \brief シリアル・ポートが送信可能か調べる
240 * \param siopcb SIOを指し示すポート・コントロール・ブロックへのポインタ
241 * \return 送信可能であれば真、不能であれば偽を返す
243 * siopcbが指し示すシリアル・ペリフェラルを調べ、送信可能なら真を返す。
245 * 送信可能か否かの判断には、送信割り込みが許可されているかどうかも含まれる。イネーブルかつ送信レジスタに空きがあるなら
246 * 送信可能である。送信の可否に割り込み許可状態を含めるのは、送信割り込み禁止状態で送信コールバックを呼ぶことを防ぐため
249 * sio_putready()関数は sio_isr()関数から送信可能かどうかをチェックするために呼ばれる。もし、可能であれば sio_isr()は
250 * シリアル制御サービスの sio_irdy_snd()コールバック関数を呼び出してしまう。コールバック禁止状態でこの関数を呼ばない
251 * ようにするには、割り込み許可状態の確認が不可欠である。割り込み許可状態の設定に関しては sio_ena_cbr()関数と
252 * sio_dis_cbr()関数を参照のこと。
254 Inline bool_t sio_putready(SIOPCB* siopcb)
257 uint32_t reg = siopcb->reg_base; /* UARTのベースアドレスを取得 */
259 /* THRが空ならば送信可能なので真を返す */
260 return (uart_read( reg, UART_LSR ) & LSR_TX_EMPTY);
264 * \brief シリアル・ポートに受信データがあるか調べる
265 * \param siopcb SIOを指し示すポート・コントロール・ブロックへのポインタ
266 * \return 送信受信データがあれば真、なければ偽を返す
268 * siopcbが指し示すシリアル・ペリフェラルを調べ、受信データがあるなら真を返す。
270 * 受信可能か否かの判断には、受信割り込みが許可されているかどうかも含まれる。イネーブルかつ受信レジスタに受信データがあるなら
271 * 受信可能である。受信の可否に割り込み許可状態を含めるのは、受信割り込み禁止状態で受信コールバックを呼ぶことを防ぐため
274 * sio_getready()関数は sio_isr() 関数から受信可能かどうかをチェックするために呼ばれる。もし、可能であれば sio_isr()は
275 * シリアル制御サービスの sio_irdy_rcv()コールバック関数を呼び出してしまう。コールバック禁止状態でこの関数を呼ばない
276 * ようにするには、割り込み許可状態の確認が不可欠である。割り込み許可状態の設定に関しては sio_ena_cbr()関数と
277 * sio_dis_cbr()関数を参照のこと。
279 Inline bool_t sio_getready(SIOPCB* siopcb)
281 uint32_t reg = siopcb->reg_base; /* UARTのベースアドレスを取得 */
283 /* RBRがいっぱいならば受信可能なので真を返す */
284 return (uart_read( reg, UART_LSR ) & LSR_RX_DATA_READY);
292 * \ingroup TOPPERS_SIO
293 * \defgroup SIOSUPPORT SIOサポート関数群
298 * \brief ターゲットのシリアル初期化
299 * \param siopid SIOのポートID
301 * siopidで指定されるターゲットのSIOペリフェラルを初期化する。初期化するのは、ストップビットやビット数といった
302 * プロトコルのほか、ボーレートも含む。この館数は、target_initialize() 関数からも呼び出され、バナー出力用の
305 * ボーレートの設定にはUARTへ供給されるクロック周波数の設定が必要であるが、これは全UARTで共通であると
306 * 仮定して決めうちしている。周波数はSIO_UART_CLOCKで指定する。単位はHzである。また、ボーレートは
308 * SIO_BAUD_RATE_DEFAULTに設定されるが、上書きしたければSIOx_BAUD_RATEを宣言する。単位はBAUDである。
310 void target_uart_init(ID siopid)
312 uint32_t reg = sioreg_table[SIOPID2INDEX(siopid)]; /* 使用するUARTのベースアドレスを取得 */
315 uart_write( reg, UART_LCR, 0 ); /* DLAB モードをいったんクリアする */
316 uart_write( reg, UART_FCR, 0 ); /* FIFO クリア*/
317 uart_write( reg, UART_IER, 0 ); /* 割り込みをディセーブルにする */
320 uart_write( reg, UART_LCR, LCR_DLAB ); /* ディバイザ設定モードに移行 */
324 #if defined(SIO_BAUD_RATE_PORT1)
325 uart_write( reg, UART_DLL, DLL((SIO_UART_CLOCK/SIO_BAUD_RATE_PORT1/16)) );
326 uart_write( reg, UART_DLM, DLM((SIO_UART_CLOCK/SIO_BAUD_RATE_PORT1/16)) );
328 uart_write( reg, UART_DLL, DLL((SIO_UART_CLOCK/SIO_BAUD_RATE_DEFAULT/16)) );
329 uart_write( reg, UART_DLM, DLM((SIO_UART_CLOCK/SIO_BAUD_RATE_DEFAULT/16)) );
333 #if defined(SIO_BAUD_RATE_PORT2)
334 uart_write( reg, UART_DLL, DLL((SIO_UART_CLOCK/SIO_BAUD_RATE_PORT2/16)) );
335 uart_write( reg, UART_DLM, DLM((SIO_UART_CLOCK/SIO_BAUD_RATE_PORT2/16)) );
337 uart_write( reg, UART_DLL, DLL((SIO_UART_CLOCK/SIO_BAUD_RATE_DEFAULT/16)) );
338 uart_write( reg, UART_DLM, DLM((SIO_UART_CLOCK/SIO_BAUD_RATE_DEFAULT/16)) );
342 #if defined(SIO_BAUD_RATE_PORT3)
343 uart_write( reg, UART_DLL, DLL((SIO_UART_CLOCK/SIO_BAUD_RATE_PORT3/16)) );
344 uart_write( reg, UART_DLM, DLM((SIO_UART_CLOCK/SIO_BAUD_RATE_PORT3/16)) );
346 uart_write( reg, UART_DLL, DLL((SIO_UART_CLOCK/SIO_BAUD_RATE_DEFAULT/16)) );
347 uart_write( reg, UART_DLM, DLM((SIO_UART_CLOCK/SIO_BAUD_RATE_DEFAULT/16)) );
351 #if defined(SIO_BAUD_RATE_PORT4)
352 uart_write( reg, UART_DLL, DLL((SIO_UART_CLOCK/SIO_BAUD_RATE_PORT4/16)) );
353 uart_write( reg, UART_DLM, DLM((SIO_UART_CLOCK/SIO_BAUD_RATE_PORT4/16)) );
355 uart_write( reg, UART_DLL, DLL((SIO_UART_CLOCK/SIO_BAUD_RATE_DEFAULT/16)) );
356 uart_write( reg, UART_DLM, DLM((SIO_UART_CLOCK/SIO_BAUD_RATE_DEFAULT/16)) );
361 /* デバイザ設定モードから、通常モードに戻す */
362 uart_write( reg, UART_LCR, 0 ); /* 通常モードに移行 */
364 /* プロトコルを設定。8bit, 1stop bit, parityなし */
365 uart_write( reg, UART_LCR, LCR_NP_8_1 ); /* 通常モードに移行 */
370 * \brief ターゲットのシリアル終了
371 * \param siopid 終了するポートの番号
376 void target_uart_term(ID siopid)
378 uint32_t reg = sioreg_table[SIOPID2INDEX(siopid)];
381 uart_write( reg, UART_IER, 0 ); /* 割り込みをディセーブルにする */
391 * \param exinf ATTINI静的APIが渡す引数
393 * porting.txtにはtarget_serial.cfgにこの関数を初期化ルーチンとして
394 * 登録する静的APIを含めることになっている( ASP 1.3.2 )。
396 * この関数はシリアル・ポート・サービス・タスク用に内部変数を初期化するだけであり、
397 * デバイスの初期化は行っていない。デバイスの初期化はsio_opn_porが呼ばれたときに毎回行われる。
399 void sio_initialize(intptr_t exinf)
403 for (i = 0; i < TNUM_PORT; i++)
405 siopcb_table[i].peripheral_index = i;
406 siopcb_table[i].reg_base = sioreg_table[i];
407 siopcb_table[i].exinf = 0;
414 * \param siopid SIOを識別する番号。1から TNUM_PORTまでの整数
415 * \param exinf 拡張情報。コールバックを呼ぶときに引数として渡す
417 * シリアル・ペリフェラルを初期化する。ペリフェラルはプロトコル、スピードなどの
418 * 設定を終え、割り込み禁止状態で待機する。この関数に続いて sio_ena_cbrが
421 * 引数extinfで渡される情報を処理する必要はない。この引数はそのまま
422 * sio_irdy_sndおよび sio_irdy_rcvコールバックに渡される。
424 * プロトコルは8bit, 1stopbit, parityなしに決めうちしていい。
426 SIOPCB *sio_opn_por(ID siopid, intptr_t exinf)
430 if (siopid > TNUM_PORT) {
434 siopcb = GET_SIOPCB(siopid);
435 siopcb->exinf = exinf;
437 target_uart_init(siopid);
445 * \param p_siopcb ポート識別用PCBへのポインタ
447 * ターゲットのポートを閉じる。ポートはディセーブルされ、割り込みは起きない。
449 void sio_cls_por(SIOPCB *p_siopcb)
451 target_uart_term(INDEX2SIOPID(p_siopcb->peripheral_index));
459 * porting.txtの8.3節で養成されている割り込みサービスルーチン。
460 * このルーチンはextinfの情報を元にどの割り込みが発生したか自動判別
463 * extinfにどのような情報を与えるかは、明言されていないように思える。
464 * CORTEX-M3版ではポート番号(1から始まってTNUM_PORTまでの識別
465 * 番号)がtarget_erial.cfgの中でATTISRのextinf引数として与えられている。
467 void sio_isr(intptr_t exinf)
469 SIOPCB* siopcb = GET_SIOPCB(exinf);
470 int32_t reg = siopcb->reg_base;
471 /* 送信コールバック可能でかつ送信可能なら、送信コールバックを呼ぶ */
472 if (sio_putready(siopcb) && ( uart_read(reg, UART_IER) & IER_TX)) {
473 sio_irdy_snd(siopcb->exinf);
475 /* 受信コールバック可能でかつ受信可能なら、受信コールバックを呼ぶ */
476 if (sio_getready(siopcb) && ( uart_read(reg, UART_IER) & IER_RX)) {
477 sio_irdy_rcv(siopcb->exinf);
484 * \param siopcb 送信するSIOポート
486 * \return 送信に成功したら真、失敗したら偽
488 * シリアル制御タスクから呼び出されて1文字送信する関数。送信できた時には真を、できなかったときには偽を返す。
489 * 送信の成否は実際の出力ではなく、送信レジスタへ書き込めたかどうかで判断してよい。この場合、送信レジスタが
490 * いっぱいであれば、送信できなかったことになる
492 bool_t sio_snd_chr(SIOPCB *siopcb, char_t c)
494 uint32_t reg = siopcb->reg_base; /* UARTのベースアドレスを取得 */
496 if (sio_putready(siopcb)) {
497 uart_write( reg, UART_THR, c);
508 * \param siopcb 受信するSIOポート
509 * \return 受信した文字 受信した文字を+0から+255までの正の値として返す。何も受信していないときには-1を返す。
511 * シリアル制御タスクから呼び出されて1文字受信する関数。何も受信していない時には、-1を返す。受信した文字は0から255までの正の数として返す。
513 int_t sio_rcv_chr(SIOPCB *siopcb)
517 uint32_t reg = siopcb->reg_base; /* UARTのベースアドレスを取得 */
519 if (sio_getready(siopcb)) {
520 c = uart_read( reg, UART_RBR ) & 0xFF;
529 * \param siopcb コールバックを許可するSIOポート
530 * \param cbrtn SIO_RDY_SND あるいは SIO_RDY_RCV
532 * シリアル制御タスクのコールバック関数の呼び出しを許可する関数。 cbrtn 引数を使って送信と受信のいずれの側で許可するかを
535 * この関数はTOPPERS/ASPのシリアル制御タスクの中から呼び出される。コールバックの許可にはペリフェラルの割り込み許可機能を使う。
537 void sio_ena_cbr(SIOPCB *siopcb, uint_t cbrtn)
539 uint32_t reg = siopcb->reg_base; /* UARTのベースアドレスを取得 */
543 uart_write( reg, UART_IER, uart_read(reg, UART_IER) | IER_TX ); /* 送信割り込みを許可 */
546 uart_write( reg, UART_IER, uart_read(reg, UART_IER) | IER_RX ); /* 受信割り込みを許可 */
556 * \param siopcb コールバックを禁止するSIOポート
557 * \param cbrtn SIO_RDY_SND あるいは SIO_RDY_RCV
559 * シリアル制御タスクのコールバック関数の呼び出しを禁止する関数。 cbrtn 引数を使って送信と受信のいずれの側で禁止するかを
562 * この関数はTOPPERS/ASPのシリアル制御タスクの中から呼び出される。コールバックの禁止にはペリフェラルの割り込み禁止機能を使う。
564 void sio_dis_cbr(SIOPCB *siopcb, uint_t cbrtn)
566 uint32_t reg = siopcb->reg_base; /* UARTのベースアドレスを取得 */
570 uart_write( reg, UART_IER, uart_read(reg, UART_IER) & ~IER_TX ); /* 送信割り込みを禁止 */
573 uart_write( reg, UART_IER, uart_read(reg, UART_IER) & ~IER_RX ); /* 受信割り込みを禁止 */
581 * \brief 1文字出力(ポーリングでの出力)
582 * \ingroup SIOSUPPORT
584 * \param siopid 出力するポートのID
586 * 出力ポートにポーリングで一文字出力する。これはTOPPERS/ASPで割り込みが有効になる前に使用する関数である。
587 * ポーリングを使うので通常タスクが使ってはいけない。
589 void sio_pol_snd_chr(char_t c, ID siopid)
591 uint32_t reg = sioreg_table[SIOPID2INDEX(siopid)]; /* 使用するUARTのベースアドレスを取得 */
593 uart_write( reg, UART_THR, c);
595 while ((uart_read( reg, UART_LSR ) & LSR_TX_EMPTY) == 0)