OSDN Git Service

thread_rcv.c: check sum calc add
[scilog/cpu2010.git] / main.c
1 /*
2  * File:   main.c
3  * sciLogger サブCPU
4  * PIC24Fj64GA004
5  * 8MHz
6  *
7  * Created on February 9, 2010, 10:53 AM
8  */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <p24FJ64GA004.h>
13 #include <libpic30.h>
14 #include <string.h>
15 #include "myuart.h"
16 #include "myspi.h"
17 #include "debug_print.h"
18 #include "ublox.h"
19 #include "myad.h"
20 #include "delay.h"
21 #include "ring.h"
22 #include "byte2var.h"
23 #include "myint.h"
24 #include "mysts.h"
25 #include "util.h"
26
27 _CONFIG1( JTAGEN_OFF & GCP_OFF & GWRP_OFF & COE_OFF & FWDTEN_OFF & ICS_PGx2 )
28 //_CONFIG2( FCKSM_CSDCMD & OSCIOFNC_ON & POSCMOD_OFF & FNOSC_FRC)
29 #pragma config FCKSM = CSDCMD, OSCIOFNC = ON, POSCMOD = OFF, FNOSC = FRC, FPBDIV = DIV_8
30
31 //#define CPU_CLOCK        10000000                         // クロック[ Hz ]
32 //#define CPU_PLL          8                                // PLL
33 //#define CLOCK_FREQUENCY  ( ( CPU_CLOCK * CPU_PLL ) / 4 )  // 動作周波数[ Hz ]
34 //#define FOSC 4000000L
35 // UART2 Debug Port
36 #define BAUDRATE2         19200L
37 // UART1 GPS
38 #define BAUDRATE1         9600L
39
40 // SPI受信データの先頭文字 送信コマンドでも使用
41 #define SPI_HEAD_CHAR   '$'
42
43 /*** ADバッファ *************************************************
44  * 50Hzデータ
45  * 1秒平均データ
46  * タイムスタンプ
47  */
48 #define ADBUF_BYTE  3   // AD 1CH 1sample dataのbyte数
49 #define ADBUF_LEN   (sizeof(ADbufType)+1)   // SPI送信1packetの長さ byte $含まず DMA問題のために+1byteしている
50
51 #define RESDATA_LEN 17  // コマンドに対する返答データ 最大長さ
52
53 // 送信データの先頭からのオフセット adbuf内のオフセット $含まない
54 #define ADBUF_OFS_SUM           962 // checksum
55
56 // SPI送信にそのまま使われるので注意!
57 // 全体のサイズが2byteの整数倍になるようにすること word align
58 typedef struct {
59     unsigned char   rescode;    // コマンドに対する返答 ACK/NAK/NUL
60     unsigned char   resdata[RESDATA_LEN];   // コマンドに対する返答データ
61     UbloxNavTimeUtc t;  // タイムスタンプ
62     long data1sec[AD_CHNUM];  // 1sec平均値
63     unsigned char data[AD_CHNUM][ADBUF_BYTE*AD_SAMPLE];  // AD_SAMPLE[Hz]のデータ
64     unsigned char suma;
65     unsigned char sumb;
66 } ADbufType;
67 //} __attribute__((__packed__)) ADbufType;
68 static ADbufType   adbuf[RING_NUM];
69
70 #define adbuf_get(buf_no)   (&adbuf[buf_no])
71 #define adbuf_data_get(buf_no)   (adbuf[buf_no].data)
72 #define adbuf_1sec_get(buf_no)   (adbuf[buf_no].data1sec)
73 #define adbuf_time_get(buf_no)   (&(adbuf[buf_no].t))
74
75 inline void adbuf_write(unsigned char buf_no, unsigned char ch, int cnt, long *data)
76 {
77     unsigned char    *ptr = (unsigned char*)data;
78     unsigned char   i;
79
80     for(i = 0; i < ADBUF_BYTE; i++) {
81         adbuf[buf_no].data[ch][ADBUF_BYTE*cnt + i] = *(ptr++);
82     }
83 }
84 // 1
85 inline void adbuf_1sec_write(char buf_no, long *data)
86 {
87     my_memcpy(adbuf_1sec_get(buf_no), data, sizeof(long) * AD_CHNUM);
88 /*    char ch;
89     for(ch = 0; ch < AD_CHNUM; ch++)
90         adbuf_1sec[buf_no][ch] = data[ch];
91 */
92 }
93 inline void adbuf_time_write(char buf_no, UbloxNavTimeUtc *t)
94 {
95 //    my_memcpy(&adbuf_t[buf_no], t, sizeof(UbloxNavTimeUtc));
96     my_memcpy(adbuf_time_get(buf_no), t, sizeof(UbloxNavTimeUtc));
97 }
98 inline void adbuf_sum_write(char buf_no, unsigned char *suma, unsigned char *sumb)
99 {
100     adbuf[buf_no].suma = *suma;
101     adbuf[buf_no].sumb = *sumb;
102 }
103
104 /**** SPI CMD受信バッファ ********************************************
105  */
106 #define SPI_RX_LEN   20  // Overoから受信するコマンド長 $含む
107 static char spi_rx_buf[SPI_RX_LEN];
108 static char spi_rx_cnt; // 受信文字数カウント 0〜SPI_RX_LEN
109
110 // 受信コマンド内のオフセット位置
111 #define CMD_OFS_CMDCODE 1
112 #define CMD_OFS_CMDDATA 2
113
114 // コマンドコード
115 #define CMD_CODE_GAIN   1
116
117 // 返答コード
118 #define RES_CODE_ACK    1
119 #define RES_CODE_NAK    2
120 #define RES_CODE_NUL    0
121
122 // 状態
123 #define CMD_STS_NONE    0   // 有効なコマンド無し
124 #define CMD_STS_RCVD    1   // 有効なコマンド受け取った
125 static char spi_cmd_sts;    // コマンド受信状態
126
127 #define spi_cmd_sts_set(i)  INTERRUPT_PROTECT(spi_cmd_sts = i)
128 #define spi_cmd_sts_get()   spi_cmd_sts
129
130
131 // ACK送信
132 void spi_res_send(unsigned char res_code, unsigned char *res_data, int data_len)
133 {
134     ADbufType *ad;
135
136     INTERRUPT_PROTECT(
137         ad = adbuf_get(ring_read1_get());
138         ad->rescode = res_code;
139         if (res_data == NULL || data_len <= 0) {
140             my_memset(ad->resdata, 0, RESDATA_LEN);
141         } else {
142             my_memcpy(ad->resdata, res_data, data_len);
143         }
144     );
145 }
146 #define spi_res_send_ack()  spi_res_send(RES_CODE_ACK, NULL, 0)
147 #define spi_res_send_nak()  spi_res_send(RES_CODE_NAK, NULL, 0)
148
149
150 // コマンドに対応する処理
151 void spi_cmd_proc(void)
152 {
153     int i;
154
155     switch(spi_rx_buf[CMD_OFS_CMDCODE]) {
156         case CMD_CODE_GAIN:
157             for(i = 0; i < AD_CHNUM; i++) {
158                 pga_gain_set(i, spi_rx_buf[CMD_OFS_CMDDATA + i]);
159             }
160             // ACK送信
161             spi_res_send_ack();
162             break;
163         default:
164             PDEBUG("spi_cmd_porc(): unknown CMD CODE\r\n");
165             // NACK送信
166             spi_res_send_nak();
167             break;
168     }
169 }
170
171 /**** ublox ************************************************
172  */
173 static UbloxNavTimeUtc gpsNow;
174 static void ublox_rcv(void)
175 {
176     unsigned char class, id;
177     unsigned int    len;
178     unsigned char   payload[128];
179 //    char    sz[128];
180     UbloxNavTimeUtc *gps = &gpsNow;
181
182     ublox_rcv_pkt(&class, &id, &len, payload);
183 //    sprintf(sz, "CLASS=%02X ID=%02X LEN=%d\r\n", class, id, len);
184 //    PDEBUG(sz);
185 //    ublox_debug_pkt_out(payload, len);
186     if (class == UBX_CLS_NAV && id == UBX_ID_NAV_TIMEUTC && len == UBX_LEN_NAV_TIMEUTC) {
187         ublox_decode_nav_timeutc(payload, gps);
188 /*        sprintf(sz, "%04u/%02d/%02d %02d:%02d:%02d.%09ld %6lums %6luns %02X\r\n",
189             gps->year, gps->month, gps->day, gps->hour, gps->min, gps->sec, gps->nano,
190             gps->tow, gps->tacc, gps->valid
191         );
192         PDEBUG(sz);
193 */
194     }
195 }
196 /**** INT1/SPI1 ***********************************************/
197 /*
198  * INT1 Int及びSPI1 IntでADのデータを取得する
199  */
200 #define ADSTS_IDLE  0
201 #define ADSTS_H 1
202 #define ADSTS_M 2
203 #define ADSTS_L 3
204
205
206 static char adint_ch;   // 取得中のCH
207 static char adint_cnt = 0;  // 0〜AD_SAMPLE-1
208 static char adint_sts = ADSTS_IDLE;
209 static long adint_add[AD_CHNUM];    // 1秒平均用加算
210
211 /**** 1PPS ********************************************/
212 static char pps_intf;
213
214 #define pps_intf_clear()  pps_intf = 0
215 #define pps_intf_set()  pps_intf = 1
216 #define pps_is_intf_enable()    (pps_intf != 0)
217
218 /**** DataOut SPI2 *********************************************/
219 #define SPI2CSpin  (PORTCbits.RC8)
220
221 // SPI2 未送信データバイト数
222 static int  dataout_cnt;
223 #define dataout_cnt_set(i)  dataout_cnt = (i)
224 #define dataout_cnt_get()  dataout_cnt
225 #define dataout_cnt_minus()  (dataout_cnt--)
226
227 // 送信位置ポインタ
228 static char    *dout_ptr;
229
230
231 /**** DRDY OUT ****************************************/
232 #define DRDY_OUT    PORTCbits.RC9
233
234
235 /*
236  * main()
237  */
238 int main(int argc, char** argv) {
239     unsigned int i;
240     // UART2 DebugPort
241     const double Baudrate2 = ( double )FCY / ( 16 * BAUDRATE2 ) - 1;
242     // ボーレートの小数点以下を四捨五入する
243     unsigned int baudrate2 = ( unsigned int )( Baudrate2 + 0.5 );
244     // UART1 GPS
245     const double Baudrate1 = ( double )FCY / ( 16 * BAUDRATE1 ) - 1;
246     // ボーレートの小数点以下を四捨五入する
247     unsigned int baudrate1 = ( unsigned int )( Baudrate1 + 0.5 );
248     char    sz[128];
249     UbloxNavTimeUtc *gps = &gpsNow;
250     ADbufType   *ad;
251     
252     /**** 割り込み禁止 ****/
253     SET_CPU_IPL( 7 );
254     __builtin_write_OSCCONL(OSCCON & 0xbf); //clear the bit 6 of OSCCONL to unlock Pin Re-map
255     // 割り込みネストenable
256     int_nest_enable();
257
258     // UART1ピン割り当て
259     RPINR18bits.U1RXR = 6;      // UART1 RX to RP6
260     RPOR2bits.RP5R =  3;        // UART1 TX(3) to RP5
261     // UART2ピン割り当て
262     RPINR19bits.U2RXR = 21;     // UART2 RX to RP21
263     RPOR10bits.RP20R = 5;       // UART2 TX(5) to RP20
264     // PIC-RDYピン割り当て
265     RPOR12bits.RP25R = 0;       // RC9
266
267     // DataOut SPI2 pin config
268     RPINR22bits.SDI2R = 13;     // SPI2 RX to RP13
269     RPINR22bits.SCK2R = 23;     // SPI2 CLK to RP23
270     RPINR23bits.SS2R = 24;      // SPI2 SS to RP24
271     RPOR11bits.RP22R = 10;      // SPI1 SDO2(10) to RP22
272     // AD SPI1 pin config
273     RPINR20bits.SDI1R = 18;     // SPI1 RX to RP18
274     RPOR8bits.RP16R = 8;        // SPI1 SCK1(8) to RP16
275     RPOR8bits.RP17R = 7;        // SPI1 SDO1(7) to RP17
276     // TRISx 1=input 0=output
277     TRISA = 0x0000;             // PortA RA7,8,9 output
278     //        5432109876543210
279     TRISB = 0b0011000011000000; // PortB RB13(RP13),RB12,RB7,RB6(RP6) input
280     TRISC = 0x01A4;             // ポートC RC8(RP24),RC7(RP23),RC5(RP21),RC2(RP18) input
281     CLKDIV = 0;                 // CPU Peripheral Clock Ratio=1:1
282     AD1PCFG = 0xFFFF;           // AN1-12input pin = Digital mode
283
284     // INT1(RP12 RB12) AD -DRDY0 setup
285     RPINR0bits.INT1R = 12;  // RP12(RB12)
286     int1_int_disable();
287     int1_level_set(4);    // Int priority
288     int1_edge_neg(); // Negative Edge
289     // INT0(RB7) GPS +PPS setup
290     int0_int_disable();
291     int0_level_set(4);    // INT Priority
292     int0_edge_pos(); // Positive Edge
293     // ChangeNotification INT, CN20(RC8), SPI2(Overo) CS0
294     cnint_int_disable();
295     CNEN2bits.CN20IE = 1;
296     CNPU2bits.CN20PUE = 1;  // Pullup ON
297     cnint_level_set(4);
298
299     adint_cnt = 0;
300     ad_cs_dis();
301     sts_set(STS_NOSYNC);
302     pps_intf_clear();
303     DRDY_OUT = 1;
304     spi_cmd_sts = CMD_STS_NONE;
305     
306     // GPS UART1初期設定 BRGH=Standard mode
307     // 9600bps 8bit nonparity 1stop nonflowcnt.
308     //                           5432109876543210
309     unsigned int U1MODEvalue = 0b1000100000000000;
310     unsigned int U1STAvalue =  0b0000010000000000;
311 //    OpenUART1( U1MODEvalue, U1STAvalue, baudrate1);
312     uart1_init( U1MODEvalue, U1STAvalue, baudrate1);
313     // DEBUG UART2初期設定 BRGH=Standard mode
314     // 9600bps 8bit nonparity 1stop nonflowcnt.
315     //                           5432109876543210
316     unsigned int U2MODEvalue = 0b1000100000000000;
317     unsigned int U2STAvalue =  0b0000010000000000;
318     uart2_init( U2MODEvalue, U2STAvalue, baudrate2);
319
320
321     spi1_init();
322     spi2_init();
323     spi1_int_disable();
324     spi2_int_disable();
325     spi2_putc(SPI_HEAD_CHAR); // 一番最初のデータ送信のためにセットしておく
326
327     PDEBUG("START\r\n");
328 //    sprintf(sz, "sizeof(ADBUF)=%d\r\n", ADBUF_LEN);
329 //    PDEBUG(sz);
330
331     // GPS UART1 受信割り込み許可
332     uart1_rx_int_enable();
333     uart1_set_int_level(4);  // 割り込みレベル デフォルト4
334     // DebugOut UART2 受信割り込み許可
335     uart2_rx_int_enable();
336     uart2_set_int_level(4);  // 割り込みレベル デフォルト4
337
338     //**** 割り込み許可 **************************************************
339     // CPU割り込み優先レベル デフォルト0 ペリフェラルはデフォルト4
340 //    SRbits.IPL = 2;
341     SET_CPU_IPL( 2 );
342
343     // UBXプロトコルのみにする
344     ublox_rcvbuf_clear();
345     ublox_send_cfg_prt(BAUDRATE1);
346     ublox_rcv_ack();
347     // TimePulse2にAD用クロック出力する
348     ublox_rcvbuf_clear();
349     ublox_send_cfg_tp5_timepulse2();
350     ublox_rcv_ack();
351     // TimePulse1をGPS時刻fixしなくても出力する
352     // pulse幅 unlocked=500msec locked=100msec
353     ublox_rcvbuf_clear();
354     ublox_send_cfg_tp5_timepulse1();
355     ublox_rcv_ack();
356     // NAV-TIMEUTC出力させる
357     ublox_send_cfg_msg();
358     ublox_rcv_ack();
359
360     // AD初期化
361     ad_reset_dis();
362     ad_start_dis();
363     ad_cs_dis();
364     //
365     ad_reset(); // -AD RESET
366     // WAIT 2^16 AD system clocks
367     delay_ms(100);
368     //
369     ad_cs_init();
370     ad_init();
371     pga_init();
372     
373     ring_init();
374     // AD SPI1 割り込み設定のみ 許可しない
375     // INT1ハンドラ内で有効にされる
376     spi1_intf_clear();
377     spi1_set_int_level(4);
378     // DataOut SPI2 割り込み許可しない CSのCN INTで許可するので
379     spi2_intf_clear();
380     spi2_set_int_level(4);
381
382     /**** ペリフェラル割り込み許可 INT1/INT0/CN ************************/
383     // INT1割り込み許可
384     int1_intf_clear();
385     int1_int_enable();    // Int enable
386     // INT0割り込み許可
387     int0_intf_clear();
388     int0_int_enable();    // Int enable
389     // ChangeNotification INT許可 SPI2(Overo) CS
390     cnint_intf_clear();
391     cnint_int_enable();
392
393     while(1) {
394         // GPSから受信してデコード
395         ublox_rcv();
396         if (gpsNow.valid == 0x07 && sts_get() == STS_NOSYNC) {
397             // 時刻有効
398             sts_set(STS_SYNCNOW0);
399         }
400         // DebugOutに1secデータ出力
401         if (ring_read2_get() != ring_write_get()) {
402             // タイムスタンプget
403             gps = adbuf_time_get(ring_read2_get());
404             sprintf(sz, "%04u/%02d/%02d %02d:%02d:%02d.%09ld,%6lums,%6luns,%02X",
405                 gps->year, gps->month, gps->day, gps->hour, gps->min, gps->sec, gps->nano,
406                 gps->tow, gps->tacc, gps->valid
407             );
408             PDEBUG(sz);
409
410 #if 1
411             // AD data get
412             char ch;
413             long    *lp;
414             lp = adbuf_1sec_get(ring_read2_get());
415             for(ch=0; ch<AD_CHNUM; ch++) {
416                 sprintf(sz, ",%+7ld", lp[ch]);
417                 PDEBUG(sz);
418             }
419             PDEBUG("\r\n");
420 #endif
421 #if 0
422             ad = adbuf_get(ring_read2_get());
423             sprintf(sz, "%02X %02X\r\n", ad->sumb, ad->suma);
424             PDEBUG(sz);
425 #endif
426             ring_read2_plus();
427         }
428         // SPIからコマンド受信
429         if (spi_cmd_sts_get() == CMD_STS_RCVD) {
430 #ifdef DEBUG_PRINT
431             PDEBUG("CMD RCV:");
432             for(i = 0; i < SPI_RX_LEN; i++) {
433                 sprintf(sz, " %02X", spi_rx_buf[i]);
434                 PDEBUG(sz);
435             }
436             PDEBUG("\r\n");
437 #endif
438             // コマンドに対応する処理
439             spi_cmd_proc();
440             // コマンド受信再開
441             spi_cmd_sts_set(CMD_STS_NONE);
442         }
443
444     }
445     
446     return (EXIT_SUCCESS);
447 }
448 /*
449  * INT0 GPS 1PPS割り込みハンドラ
450  * 
451  *
452  */
453 void __attribute__((interrupt, no_auto_psv, shadow)) _INT0Interrupt(void)
454 {
455     // AD STARTピン=H
456     ad_start_ena();
457
458     int0_intf_clear();
459     pps_intf_set();
460     /****AD同期!!!!!!!!!!!!!!!*/
461     // AD個数カウンタ=SAMP_FREQ-1
462     adint_cnt = AD_SAMPLE - 1;
463
464     // ADバッファにタイムスタンプ付ける
465     adbuf_time_write(ring_write_get(), &gpsNow);
466
467     // AD START信号による同期
468     if (sts_get() == STS_SYNCNOW0) {
469         // AD STARTピン=L
470         ad_start_dis();
471         sts_set(STS_SYNCNOW1);
472     } else if (sts_get() == STS_SYNCNOW1) {
473         // AD STARTピン=H 関数先頭で行っているのでここではやらない
474         sts_set(STS_SYNCWAIT);
475     } else if (sts_get() == STS_SYNCWAIT) {
476         sts_set(STS_SYNCED);
477     }
478 }
479
480 /*
481  * INT1(RP12) AD DRDY0割り込みハンドラ
482  * Negativ Edge
483  * SPI1受信開始してSPI1割り込み有効にする
484  *
485  */
486 void __attribute__((interrupt, no_auto_psv)) _INT1Interrupt(void)
487 //void _ISR _INT1Interrupt(void)
488 {
489     int1_intf_clear();
490     if (!ad_is_drdy0_enable()) {
491         return;
492     }
493
494     adint_ch = 0;
495     adint_sts = ADSTS_H;
496     if (adint_cnt == 0) {
497         my_memset(adint_add, 0, sizeof(adint_add));
498     }
499
500     ad_cs(adint_ch);    // CSx=L
501     spi1_rx_overrun_clear();
502     // 前に受信したデータをクリア
503     spi1_getc();
504     // SPI割り込みON
505     spi1_intf_clear();
506     spi1_int_enable();
507     // 送信
508     spi1_putc(0);
509 }
510 /*
511  * AD SPI1 Interrupt Handler
512  * ADから受信したデータをADバッファに格納する
513  * 6CHぶん受信したらSPI1割り込みをOFF
514  * 
515  */
516 //void _ISR _SPI1Interrupt(void)
517 void __attribute__((interrupt, auto_psv)) _SPI1Interrupt(void)
518 {
519     static unsigned char in[3];
520     unsigned char c;
521     long    l;
522 //int i;
523 //unsigned char   *ptr;
524
525     spi1_intf_clear();
526     c = spi1_getc();
527     spi1_rx_overrun_clear();
528
529     switch(adint_sts) {
530         case ADSTS_H:
531             in[2] = c;
532             adint_sts = ADSTS_M;
533             spi1_putc(0);
534             break;
535         case ADSTS_M:
536             in[1] = c;
537             adint_sts = ADSTS_L;
538             spi1_putc(0);
539             break;
540         case ADSTS_L:
541             // CSx=H
542             ad_cs_dis();
543             in[0] = c;
544             l = byte3_to_long(in);
545             // バッファに書きこみ
546             adbuf_write(ring_write_get(), adint_ch, adint_cnt, &l);
547             // 1秒平均用加算
548             adint_add[adint_ch] += l;
549             // CH進める
550             adint_ch++;
551             if (adint_ch >= AD_CHNUM) {
552                 // 全CHデータgetした
553                 adint_cnt++;
554                 if (adint_cnt >= AD_SAMPLE) {
555                     // 1secぶんのデータgetした
556                     // DRDY->H DRDY=Lの時でもDRDYのエッジを作るため
557                     DRDY_OUT = 1;
558                     // 1sec平均する
559                     char ch;
560                     for(ch = 0; ch < AD_CHNUM; ch++) {
561                         adint_add[ch] /= adint_cnt;
562                     }
563                     // 1secバッファに書きこみ
564                     adbuf_1sec_write(ring_write_get(), adint_add);
565 #if 0
566 ptr = (unsigned char*)adbuf_get(ring_write_get());
567 ptr += 62;
568             for(i = 0; i < 900; i++) {
569                 suma += *ptr++;
570                 sumb += suma;
571             }
572 #endif
573                     // バッファ書き込み位置+1
574                     ring_write_plus();
575                     // 次のADバッファをゼロクリア
576                     my_memset(adbuf_get(ring_write_get()), 0, ADBUF_LEN);
577                     adint_cnt = 0;
578                     // DRDY->L
579 // TODO: waitカウンタで制限
580                     DRDY_OUT = 0;
581                 }
582                 spi1_int_disable(); // SPI割り込みOFF
583                 adint_sts = ADSTS_IDLE;
584             } else {
585                 // 次のCHへ
586                 ad_cs(adint_ch);    // CSx=L
587                 // 送信
588                 spi1_putc(0);
589                 adint_sts = ADSTS_H;
590             }
591
592             break;
593         default:
594             spi1_int_disable(); // SPI割り込みOFF
595             adint_sts = ADSTS_IDLE;
596             break;
597     }
598
599 }
600 static unsigned char    suma;
601 static unsigned char    sumb;
602
603 /*
604  * DataOut SPI2 Interrupt Handler
605  * TX FIFOに1byteの空きが出来ると発生
606  */
607 void __attribute__((interrupt, no_auto_psv)) _SPI2Interrupt(void)
608 {
609     unsigned char   rx;
610
611     spi2_intf_clear();
612     // 送信 AD DATA
613     while(SPI2_TBF == 0) {
614         // checksum
615         if ((ADBUF_LEN - dataout_cnt_get()) == ADBUF_OFS_SUM) {
616             // checksum書き込み
617             adbuf_sum_write(ring_read1_get(), &suma, &sumb);
618         }
619         suma += (unsigned char)*dout_ptr;
620         sumb += suma;
621
622         if (dataout_cnt_get() <= 0) break;
623         spi2_putc(*dout_ptr++);
624         dataout_cnt_minus();
625     }
626     // 受信 CMD
627     while(SPI2_SRXMPT == 0) {
628         rx = spi2_getc();
629         if (spi_cmd_sts == CMD_STS_NONE && spi_rx_cnt < SPI_RX_LEN) {
630             spi_rx_buf[spi_rx_cnt] = rx;
631             spi_rx_cnt++;
632             if (spi_rx_cnt >= SPI_RX_LEN) {
633                 if (spi_rx_buf[CMD_OFS_CMDCODE] != 0) {
634                     spi_cmd_sts = CMD_STS_RCVD;
635                 }
636             }
637         }
638     }
639
640     // オーバーランエラーならばクリアする
641     if (SPI2STATbits.SPIROV == 1) SPI2STATbits.SPIROV = 0;
642
643 }
644 /*
645  * Overo SPI2 CS Input Change Notification
646  * Interrupt Handler
647  *
648  */
649 void __attribute__((interrupt, no_auto_psv)) _CNInterrupt(void)
650 {
651     cnint_intf_clear();
652     if (SPI2CSpin == 1) {
653         // CS=H
654         // SPI2割り込みOFF
655         spi2_int_disable();
656         // SPI2をリセットしてTX/RX FIFOクリア
657         SPI2STATbits.SPIEN = 0;
658         asm("nop");
659         SPI2STATbits.SPIEN = 1;
660         asm("nop");
661         SPI2BUF;    // RBF->0
662         // $->TX FIFO
663         spi2_putc(SPI_HEAD_CHAR);
664         // リングバッファ読み込み位置+1
665         ring_read1_plus();
666     } else {
667         // CS=L
668         // リングバッファ読み込み位置get
669         dout_ptr = (char*)adbuf_get(ring_read1_get());
670         // SPI送信の一番最初
671         dataout_cnt_set(ADBUF_LEN);
672         suma = 0;
673         sumb = 0;
674         // SPI2 TX FIFOに送信データ書き込み
675         while(SPI2_TBF == 0) {
676             suma += (unsigned char)*dout_ptr;
677             sumb += suma;
678             if (dataout_cnt_get() <= 0) break;
679             spi2_putc(*dout_ptr++);
680             dataout_cnt_minus();
681         }
682         if (spi_cmd_sts == CMD_STS_NONE) {
683             // SPI受信文字数カウンタクリア
684             spi_rx_cnt = 0;
685         }
686         // SPI2割り込みON
687         spi2_int_enable();
688         // DRDY=H
689         DRDY_OUT = 1;
690     }
691 }