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>
20 #elif defined(_COMMON_BF548)
21 #include <cdefBF548.h>
24 #error "This processor is not supported"
33 #define I2C_SYSLOG(level,msg) syslog( level, msg )
35 #define I2C_SYSLOG(level,msg)
40 * \brief チップ上のI2Cペリフェラルの数
45 * \brief I2C ペリフェラルのタイムアウト時間(mSec)
47 #define I2C_TIMEOUT 100
50 * \brief TWIペリフェラルの管理用ステート型。内部ステートマシンの状態値。
69 struct I2C_MASTER_CONTROL_TYPE {
70 ID signal; /**< データの送受信が全部終わったときに割り込みハンドラからタスクに知らせるためのセマフォ */
71 ID blocking; /**< I2Cペリフェラルへの排他アクセスのためのセマフォ */
72 unsigned short intr_state; /**< TWIペリフェラルの割り込みステータスのコピー **/
73 volatile unsigned short * clkdiv; /**< TWI_CLCKDIVレジスタのアドレス **/
74 volatile unsigned short * control; /**< TWI_CONTROLレジスタのアドレス **/
75 volatile unsigned short * master_ctl; /**< TWI_MASTER_CTLレジスタのアドレス **/
76 volatile unsigned short * master_stat; /**< TWI_MASTER_STATレジスタのアドレス **/
77 volatile unsigned short * master_addr; /**< TWI_MASTER_ADDRレジスタのアドレス **/
78 volatile unsigned short * int_stat; /**< TWI_MASTER_STATレジスタのアドレス **/
79 volatile unsigned short * int_mask; /**< TWI_INT_MASKレジスタのアドレス **/
80 volatile unsigned short * fifo_ctl; /**< TWI_FIFO_CTLレジスタのアドレス **/
81 volatile unsigned short * fifo_stat; /**< TWI_FIFO_STATレジスタのアドレス **/
82 volatile unsigned short * xmt_data8; /**< TWI_XMT_DATA8レジスタのアドレス **/
83 volatile unsigned short * rcv_data8; /**< TWI_RCV_DATA8レジスタのアドレス **/
84 volatile unsigned short * slave_ctl; /**< TWI_MASTER_CTLレジスタのアドレス **/
89 * \brief i2cペリフェラルを管理するための構造体群。
91 static struct I2C_MASTER_CONTROL_TYPE i2c_control[I2CNUM];
94 int i2c_master_write( int peripheral, int slave, unsigned char write_data[], int write_count )
96 // read のための引数を0にしておくと、writeのみがおこなわれる
97 return i2c_master_write_read( peripheral, slave, write_data, write_count, 0, 0);
100 int i2c_master_read( int peripheral, int slave, unsigned char read_data[], int read_count )
102 // write のための引数を0にしておくと、readのみがおこなわれる
103 return i2c_master_write_read( peripheral, slave, 0, 0, read_data, read_count);
107 int i2c_master_write_read( int peripheral, int slave, unsigned char write_data[], int write_count, unsigned char read_data[], int read_count)
109 struct I2C_MASTER_CONTROL_TYPE *twi;
110 BOOL read, write, rstart, quit;
111 unsigned char *wptr, *rptr;
112 enum I2C_STATE state; /**< I2Cペリフェラルハンドラの内部状態 */
113 PRI old_priority; // タスクの優先順位を保存しておくための変数
115 // 可読性向上のため、TWI管理構造体のポインタを設定する。
116 twi = &i2c_control[peripheral];
118 // 送受信ポインタ.とかくこの世は生きにくい
122 // この代入は必要ないが、警告がうるさいので
129 // バッファがNULLだったり長さが0のパラメタは転送に使わない
130 write = ( write_data != NULL ) && ( write_count != 0 );
131 read = ( read_data != NULL ) && ( read_count != 0 );
133 // パラメタの組み合わせによって初期状態が変わる
135 state = I2C_XMTRCV_ENTRY;
136 else if ( write && ! read )
137 state = I2C_XMT_ENTRY;
138 else if ( ! write && read )
139 state = I2C_RCV_ENTRY;
141 return I2C_ERR_WRONGPARAM;
143 if ( write_count > 254 || read_count > 254 )
144 return I2C_ERR_TOOLONGBUFFER;
147 // peripheral 引数で指定されたi2cペリフェラルを排他的に使うためのPV処理。
149 wai_sem(twi->blocking);
151 // タスクの優先順位を一旦引き上げる。これは、TWIのレスポンスを保証するためである
152 get_pri( TSK_SELF, &old_priority );
153 chg_pri( TSK_SELF, TMAX_TPRI );
155 // SPIスレーブデバイスのアドレスを設定(7bit)
156 *twi->master_addr = slave;
159 *twi->fifo_ctl = XMTFLUSH | RCVFLUSH;
163 *twi->fifo_ctl = XMTINTLEN; // 割り込みスレシホールドは送受とも1バイト、FLUSHはクリアする
170 I2C_SYSLOG(LOG_NOTICE, "I2C_XMT_ENTRY" );
172 *twi->master_ctl = ( write_count<<6 ) | MEN; // no rstart, transmit, no fast mode;
173 state = I2C_XMT_NEXT_BYTE;
175 case I2C_XMTRCV_ENTRY :
176 I2C_SYSLOG(LOG_NOTICE, "I2C_XMTRCV_ENTRY" );
178 *twi->master_ctl = ( write_count<<6 ) | RSTART | MEN; // rstart, transmit, no fast mode;
179 state = I2C_XMT_NEXT_BYTE;
182 I2C_SYSLOG(LOG_NOTICE, "I2C_RCV_ENTRY" );
184 *twi->master_ctl = ( read_count<<6 ) | MDIR | MEN; // no rstart, receive, no fast mode;
185 state = I2C_RCV_WAIT;
188 I2C_SYSLOG(LOG_NOTICE, "I2C_XMT_WAIT" );
189 // 割り込みハンドラが送信割り込みを通知するまで待つ
190 if ( E_OK != twai_sem(twi->signal, I2C_TIMEOUT))
192 twi->intr_state = I2C_ERR_TIMEOUT | *twi->int_stat; // エラーなら割り込みステータスを併記
199 I2C_SYSLOG(LOG_NOTICE, "I2C_XMT_INT" );
200 if ( twi->intr_state & MERR ) // エラーならすぐ終了
202 else if ( ( twi->intr_state & MCOMP ) && rstart) // MCOMP かつ RSTARTなら受信へ
203 state = I2C_RCV_ENTRY;
204 else if ( twi->intr_state & MCOMP ){ // RSTARTがないMCOMPなら終了
205 twi->intr_state &= ~MCOMP;
209 state = I2C_XMT_NEXT_BYTE;
211 case I2C_XMT_NEXT_BYTE :
212 I2C_SYSLOG(LOG_NOTICE, "I2C_XMT_NEXT_BYTE" );
213 *twi->xmt_data8 = *(wptr++); // 1バイト送信
214 state = I2C_XMT_WAIT; // 次の送信待
217 I2C_SYSLOG(LOG_NOTICE, "I2C_RCV_WAIT" );
218 // 割り込みハンドラが受信割り込みを通知するまで待つ
219 if ( E_OK != twai_sem(twi->signal, I2C_TIMEOUT))
221 twi->intr_state = I2C_ERR_TIMEOUT | *twi->int_stat; // エラーなら割り込みステータスを併記
228 I2C_SYSLOG(LOG_NOTICE, "I2C_RCV_INT" );
229 if ( twi->intr_state & MERR) // エラーならすぐ終了
231 else if ( twi->intr_state & MCOMP ){ // 終了ならエラークリア
232 twi->intr_state &= ~MCOMP;
236 state = I2C_RCV_NEXT_BYTE;
238 case I2C_RCV_NEXT_BYTE :
239 I2C_SYSLOG(LOG_NOTICE, "I2C_RCV_NEXT_BYTE" );
240 *(rptr++) = *twi->rcv_data8; // 1バイト受信
241 state = I2C_RCV_WAIT; // 次の受信待
244 I2C_SYSLOG(LOG_NOTICE, "I2C_EXIT" );
245 * twi->master_ctl = 0; // マスターをディセーブルして終了
252 chg_pri( TSK_SELF, old_priority);
255 sig_sem(twi->blocking);
257 // 割り込みステータスを返す。正常終了なら0
258 return twi->intr_state;
262 * \brief i2c 割り込みサービスルーチン本体
263 * \param peripheral I2Cペリフェラル番号。0から始まる。
265 * 割り込みサービスルーチンから呼び出す。この関数が割り込みハンドラの実体である。
266 * チップに複数のTWIペリフェラルがある場合には、引数に当該TWIペリフェラル番号を与えて呼び出す。
268 * 関数内部では、タスクに割り込みが入ったことを知らせ、ペリフェラルの割り込みステータスを
271 static void i2c_master_handler( int peripheral )
273 struct I2C_MASTER_CONTROL_TYPE *twi;
275 // 可読性向上のため、TWI管理構造体のポインタを設定する。
276 twi = &i2c_control[peripheral];
278 // TWIペリフェラルの割り込みステータスを取得し、コピーを保存する。
279 // コピーを保存するのは、このあと割り込みクリアで消えるからである。
280 twi->intr_state = *twi->int_stat;
282 // 割り込みクリア。すべての割り込み要素をクリアしてしまう。ステータスはコピーしているのでタスクで処理する。
283 *twi->int_stat = 0xFF;
288 /* 通知はセマフォを使う。タスクは i2c_master_write_read()の中で待っている。 */
289 isig_sem(twi->signal);
295 * TOPPERS/JSPでは、DEF_INHから割り込みハンドラに引数を渡せない。そのため、この関数内で
296 * i2c_master_handler() を引数0決め打ちで呼ぶ。
298 void i2c0_master_handler(void)
300 i2c_master_handler( 0 );
306 * \param exinf ペリフェラル番号。TWI0ならば、0を渡す。
308 * I2C用のコントロールブロックのI2C相当部分を初期化する。
309 * 現段階ではTWI0にしか対応していない。
311 void i2c_master_initialize(VP_INT exinf)
313 struct I2C_MASTER_CONTROL_TYPE *twi;
314 unsigned int peripheral = (unsigned int)exinf;
316 // 可読性向上のため、TWI管理構造体のポインタを設定する。
317 twi = &i2c_control[peripheral];
319 twi->blocking = SEM_I2C0_BLOCK; // ペリフェラルブロック用セマフォ
320 twi->signal = SEM_I2C0_SIGNAL; // 割り込み・タスク通信用セマフォ
324 twi->clkdiv = pTWI_CLKDIV ;
325 twi->control = pTWI_CONTROL ;
326 twi->master_ctl = pTWI_MASTER_CTL ;
327 twi->master_stat = pTWI_MASTER_STAT ;
328 twi->master_addr = pTWI_MASTER_ADDR ;
329 twi->int_stat = pTWI_INT_STAT ;
330 twi->int_mask = pTWI_INT_MASK ;
331 twi->fifo_ctl = pTWI_FIFO_CTL ;
332 twi->fifo_stat = pTWI_FIFO_STAT ;
333 twi->xmt_data8 = pTWI_XMT_DATA8 ;
334 twi->rcv_data8 = pTWI_RCV_DATA8 ;
335 twi->slave_ctl = pTWI_SLAVE_CTL ;
337 twi->clkdiv = pTWI0_CLKDIV ;
338 twi->control = pTWI0_CONTROL ;
339 twi->master_ctl = pTWI0_MASTER_CTL ;
340 twi->master_stat = pTWI0_MASTER_STAT ;
341 twi->master_addr = pTWI0_MASTER_ADDR ;
342 twi->int_stat = pTWI0_INT_STAT ;
343 twi->int_mask = pTWI0_INT_MASK ;
344 twi->fifo_ctl = pTWI0_FIFO_CTL ;
345 twi->fifo_stat = pTWI0_FIFO_STAT ;
346 twi->xmt_data8 = pTWI0_XMT_DATA8 ;
347 twi->rcv_data8 = pTWI0_RCV_DATA8 ;
348 twi->slave_ctl = pTWI0_SLAVE_CTL ;
351 *twi->control = 0; // TWI をディセーブル
352 *twi->master_ctl = 0; // マスター機能をディセーブル
353 *twi->slave_ctl = 0; // スレーブ機能をディセーブル
355 *twi->control = TWI_ENA | (SYSCLOCK/10000000); // HWRによると、プリスケール値はSYSCLKを10MHzで割ったものでなければならない。
356 *twi->clkdiv = 30<<8 | 70; // TWI内部クロック10MHzに対して、100kHzのI2Cクロックは100分の1である
358 // 割り込みイネーブル設定。送受割り込み、完了割り込み及びエラー割り込み。
359 *twi->int_mask = MCOMP | MERR | XMTSERV | RCVSERV;
361 // システム割り込みをイネーブルにする。