2 * \file i2c_subsystem.c
3 * \brief i2cペリフェラルをマスターモードで使うためのサブシステム
5 * CMSISを使い、i2cペリフェラルをマスターモードで使用する
7 #include "i2c_subsystem.h"
9 #include "s_services.h"
10 #include <t_services.h>
13 #include <cdefBF592-A.h>
14 #elif defined(_COMMON_BF506)
15 #include <cdefBF506F.h>
16 #elif defined(_COMMON_BF518)
17 #include <cdefBF518.h>
18 #elif defined(_COMMON_BF537)
19 #include <cdefBF537.h>
21 #error "This processor is not supported"
30 #define I2C_SYSLOG(level,msg) syslog( level, msg )
32 #define I2C_SYSLOG(level,msg)
37 * \brief チップ上のI2Cペリフェラルの数
42 * \brief I2C ペリフェラルのタイムアウト時間(mSec)
44 #define I2C_TIMEOUT 100
47 * \brief TWIペリフェラルの管理用ステート型。内部ステートマシンの状態値。
66 struct I2C_MASTER_CONTROL_TYPE {
67 ID signal; /**< データの送受信が全部終わったときに割り込みハンドラからタスクに知らせるためのセマフォ */
68 ID blocking; /**< I2Cペリフェラルへの排他アクセスのためのセマフォ */
69 unsigned short intr_state; /**< TWIペリフェラルの割り込みステータスのコピー **/
70 volatile unsigned short * clkdiv; /**< TWI_CLCKDIVレジスタのアドレス **/
71 volatile unsigned short * control; /**< TWI_CONTROLレジスタのアドレス **/
72 volatile unsigned short * master_ctl; /**< TWI_MASTER_CTLレジスタのアドレス **/
73 volatile unsigned short * master_stat; /**< TWI_MASTER_STATレジスタのアドレス **/
74 volatile unsigned short * master_addr; /**< TWI_MASTER_ADDRレジスタのアドレス **/
75 volatile unsigned short * int_stat; /**< TWI_MASTER_STATレジスタのアドレス **/
76 volatile unsigned short * int_mask; /**< TWI_INT_MASKレジスタのアドレス **/
77 volatile unsigned short * fifo_ctl; /**< TWI_FIFO_CTLレジスタのアドレス **/
78 volatile unsigned short * fifo_stat; /**< TWI_FIFO_STATレジスタのアドレス **/
79 volatile unsigned short * xmt_data8; /**< TWI_XMT_DATA8レジスタのアドレス **/
80 volatile unsigned short * rcv_data8; /**< TWI_RCV_DATA8レジスタのアドレス **/
81 volatile unsigned short * slave_ctl; /**< TWI_MASTER_CTLレジスタのアドレス **/
86 * \brief i2cペリフェラルを管理するための構造体群。
88 static struct I2C_MASTER_CONTROL_TYPE i2c_control[I2CNUM];
91 int i2c_master_write( int peripheral, int slave, unsigned char write_data[], int write_count )
93 // read のための引数を0にしておくと、writeのみがおこなわれる
94 return i2c_master_write_read( peripheral, slave, write_data, write_count, 0, 0);
97 int i2c_master_read( int peripheral, int slave, unsigned char read_data[], int read_count )
99 // write のための引数を0にしておくと、readのみがおこなわれる
100 return i2c_master_write_read( peripheral, slave, 0, 0, read_data, read_count);
104 int i2c_master_write_read( int peripheral, int slave, unsigned char write_data[], int write_count, unsigned char read_data[], int read_count)
106 struct I2C_MASTER_CONTROL_TYPE *twi;
107 BOOL read, write, rstart, quit;
108 unsigned char *wptr, *rptr;
109 enum I2C_STATE state; /**< I2Cペリフェラルハンドラの内部状態 */
110 PRI old_priority; // タスクの優先順位を保存しておくための変数
112 // 可読性向上のため、TWI管理構造体のポインタを設定する。
113 twi = &i2c_control[peripheral];
115 // 送受信ポインタ.とかくこの世は生きにくい
119 // この代入は必要ないが、警告がうるさいので
126 // バッファがNULLだったり長さが0のパラメタは転送に使わない
127 write = ( write_data != NULL ) && ( write_count != 0 );
128 read = ( read_data != NULL ) && ( read_count != 0 );
130 // パラメタの組み合わせによって初期状態が変わる
132 state = I2C_XMTRCV_ENTRY;
133 else if ( write && ! read )
134 state = I2C_XMT_ENTRY;
135 else if ( ! write && read )
136 state = I2C_RCV_ENTRY;
138 return I2C_ERR_WRONGPARAM;
140 if ( write_count > 254 || read_count > 254 )
141 return I2C_ERR_TOOLONGBUFFER;
144 // peripheral 引数で指定されたi2cペリフェラルを排他的に使うためのPV処理。
146 wai_sem(twi->blocking);
148 // タスクの優先順位を一旦引き上げる。これは、TWIのレスポンスを保証するためである
149 get_pri( TSK_SELF, &old_priority );
150 chg_pri( TSK_SELF, TMAX_TPRI );
152 // SPIスレーブデバイスのアドレスを設定(7bit)
153 *twi->master_addr = slave;
156 *twi->fifo_ctl = XMTFLUSH | RCVFLUSH;
160 *twi->fifo_ctl = XMTINTLEN; // 割り込みスレシホールドは送受とも1バイト、FLUSHはクリアする
167 I2C_SYSLOG(LOG_NOTICE, "I2C_XMT_ENTRY" );
169 *twi->master_ctl = ( write_count<<6 ) | MEN; // no rstart, transmit, no fast mode;
170 state = I2C_XMT_NEXT_BYTE;
172 case I2C_XMTRCV_ENTRY :
173 I2C_SYSLOG(LOG_NOTICE, "I2C_XMTRCV_ENTRY" );
175 *twi->master_ctl = ( write_count<<6 ) | RSTART | MEN; // rstart, transmit, no fast mode;
176 state = I2C_XMT_NEXT_BYTE;
179 I2C_SYSLOG(LOG_NOTICE, "I2C_RCV_ENTRY" );
181 *twi->master_ctl = ( read_count<<6 ) | MDIR | MEN; // no rstart, receive, no fast mode;
182 state = I2C_RCV_WAIT;
185 I2C_SYSLOG(LOG_NOTICE, "I2C_XMT_WAIT" );
186 // 割り込みハンドラが送信割り込みを通知するまで待つ
187 if ( E_OK != twai_sem(twi->signal, I2C_TIMEOUT))
189 twi->intr_state = I2C_ERR_TIMEOUT | *twi->int_stat; // エラーなら割り込みステータスを併記
196 I2C_SYSLOG(LOG_NOTICE, "I2C_XMT_INT" );
197 if ( twi->intr_state & MERR ) // エラーならすぐ終了
199 else if ( ( twi->intr_state & MCOMP ) && rstart) // MCOMP かつ RSTARTなら受信へ
200 state = I2C_RCV_ENTRY;
201 else if ( twi->intr_state & MCOMP ){ // RSTARTがないMCOMPなら終了
202 twi->intr_state &= ~MCOMP;
206 state = I2C_XMT_NEXT_BYTE;
208 case I2C_XMT_NEXT_BYTE :
209 I2C_SYSLOG(LOG_NOTICE, "I2C_XMT_NEXT_BYTE" );
210 *twi->xmt_data8 = *(wptr++); // 1バイト送信
211 state = I2C_XMT_WAIT; // 次の送信待
214 I2C_SYSLOG(LOG_NOTICE, "I2C_RCV_WAIT" );
215 // 割り込みハンドラが受信割り込みを通知するまで待つ
216 if ( E_OK != twai_sem(twi->signal, I2C_TIMEOUT))
218 twi->intr_state = I2C_ERR_TIMEOUT | *twi->int_stat; // エラーなら割り込みステータスを併記
225 I2C_SYSLOG(LOG_NOTICE, "I2C_RCV_INT" );
226 if ( twi->intr_state & MERR) // エラーならすぐ終了
228 else if ( twi->intr_state & MCOMP ){ // 終了ならエラークリア
229 twi->intr_state &= ~MCOMP;
233 state = I2C_RCV_NEXT_BYTE;
235 case I2C_RCV_NEXT_BYTE :
236 I2C_SYSLOG(LOG_NOTICE, "I2C_RCV_NEXT_BYTE" );
237 *(rptr++) = *twi->rcv_data8; // 1バイト受信
238 state = I2C_RCV_WAIT; // 次の受信待
241 I2C_SYSLOG(LOG_NOTICE, "I2C_EXIT" );
242 * twi->master_ctl = 0; // マスターをディセーブルして終了
249 chg_pri( TSK_SELF, old_priority);
252 sig_sem(twi->blocking);
254 // 割り込みステータスを返す。正常終了なら0
255 return twi->intr_state;
259 * \brief i2c 割り込みサービスルーチン本体
260 * \param peripheral I2Cペリフェラル番号。0から始まる。
262 * 割り込みサービスルーチンから呼び出す。この関数が割り込みハンドラの実体である。
263 * チップに複数のTWIペリフェラルがある場合には、引数に当該TWIペリフェラル番号を与えて呼び出す。
265 * 関数内部では、タスクに割り込みが入ったことを知らせ、ペリフェラルの割り込みステータスを
268 static void i2c_master_handler( int peripheral )
270 struct I2C_MASTER_CONTROL_TYPE *twi;
272 // 可読性向上のため、TWI管理構造体のポインタを設定する。
273 twi = &i2c_control[peripheral];
275 // TWIペリフェラルの割り込みステータスを取得し、コピーを保存する。
276 // コピーを保存するのは、このあと割り込みクリアで消えるからである。
277 twi->intr_state = *twi->int_stat;
279 // 割り込みクリア。すべての割り込み要素をクリアしてしまう。ステータスはコピーしているのでタスクで処理する。
280 *twi->int_stat = 0xFF;
285 /* 通知はセマフォを使う。タスクは i2c_master_write_read()の中で待っている。 */
286 isig_sem(twi->signal);
292 * TOPPERS/JSPでは、DEF_INHから割り込みハンドラに引数を渡せない。そのため、この関数内で
293 * i2c_master_handler() を引数0決め打ちで呼ぶ。
295 void i2c0_master_handler(void)
297 i2c_master_handler( 0 );
303 * \param exinf ペリフェラル番号。TWI0ならば、0を渡す。
305 * I2C用のコントロールブロックのI2C相当部分を初期化する。
307 void i2c_master_initialize(VP_INT exinf)
309 struct I2C_MASTER_CONTROL_TYPE *twi;
310 unsigned int peripheral = (unsigned int)exinf;
312 // 可読性向上のため、TWI管理構造体のポインタを設定する。
313 twi = &i2c_control[peripheral];
315 twi->blocking = SEM_I2C0_BLOCK; // ペリフェラルブロック用セマフォ
316 twi->signal = SEM_I2C0_SIGNAL; // 割り込み・タスク通信用セマフォ
318 twi->clkdiv = pTWI_CLKDIV ;
319 twi->control = pTWI_CONTROL ;
320 twi->master_ctl = pTWI_MASTER_CTL ;
321 twi->master_stat = pTWI_MASTER_STAT ;
322 twi->master_addr = pTWI_MASTER_ADDR ;
323 twi->int_stat = pTWI_INT_STAT ;
324 twi->int_mask = pTWI_INT_MASK ;
325 twi->fifo_ctl = pTWI_FIFO_CTL ;
326 twi->fifo_stat = pTWI_FIFO_STAT ;
327 twi->xmt_data8 = pTWI_XMT_DATA8 ;
328 twi->rcv_data8 = pTWI_RCV_DATA8 ;
329 twi->slave_ctl = pTWI_SLAVE_CTL ;
332 *twi->control = 0; // TWI をディセーブル
333 *twi->master_ctl = 0; // マスター機能をディセーブル
334 *twi->slave_ctl = 0; // スレーブ機能をディセーブル
336 *twi->control = TWI_ENA | (SYSCLOCK/10000000); // HWRによると、プリスケール値はSYSCLKを10MHzで割ったものでなければならない。
337 *twi->clkdiv = 30<<8 | 70; // TWI内部クロック10MHzに対して、100kHzのI2Cクロックは100分の1である
339 // 割り込みイネーブル設定。送受割り込み、完了割り込み及びエラー割り込み。
340 *twi->int_mask = MCOMP | MERR | XMTSERV | RCVSERV;
342 // システム割り込みをイネーブルにする。