気分を変えて、同期シリアル通信でキャラクタ液晶を制御したいと考えた。
結論から書くと、以下の2点の課題から、表示速度はすこぶる遅い。
1.仲介役のPICマイコンの動作速度は4MHz(内臓のオシレーターを使ったため)
2.やっぱりGPIO出力が間延びするから1クロック4msのディレーを入れた
16文字のデータを送るのに、現状1.3秒かかる。
いざまとめるとこんなものなのだけど、なかなか時間がかかったし、
間延び問題が気になる・・・。
ハード
FON2405EのGPIO---CLK,DATA---PICマイコン---キャラクタ液晶
ソフト
1.gpioのドライバ
2.gpioのアプリ
3.PICマイコンのファーム
1.gpioのドライバ
標準のものから変更なし
RALINK_GPIO_WRITE_BYTEを使用。
今までの試行錯誤は何だったんだ・・・・。
2.gpioのアプリ
変更点
オプション[s]を追加
s <gpio clk> <gpio data> <delaytime> <char>
これを指定するとgptio_test_write_srを呼ぶようにした。
usleepを使うと4ms以下にはならないようだし、
ドライバの方で、udelayを使って短くしても、
前回の間延び問題のように不安定になってしまう。
なので、CLKの変化のタイミングだけusleepを使って、
DATAのセット部分はディレーなしにした。
多少は速くなった。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void gpio_test_write_sr(int gpio_clk, int gpio_data,int delaytime, unsigned char *c){ | |
gpio_write_int(RALINK_GPIO_DATA_MASK); | |
int i; | |
printf("gpio_write_sr Start:CLK=%d DATA=%d\n",gpio_clk,gpio_data); | |
struct timeval s,f; | |
gettimeofday(&s,NULL); | |
for(i=0;i<17;i++){ | |
if(*(c+i) == '\0'){ break;} | |
gpio_write_byte3(gpio_clk,gpio_data,*(c+i)); | |
usleep(delaytime); //10ms | |
//sleep(1); | |
} | |
gettimeofday(&f,NULL); | |
printf("Total Time=%dms\n",(f.tv_sec-s.tv_sec)*1000+(f.tv_usec-s.tv_usec)/1000); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
int gpio_write_byte3(int port_clk,int port_data,unsigned char c){ | |
int idx = 1, fd, req, i, value, tmp, udelay; | |
int shift_clk = port_clk - 8; | |
int shift_data = port_data - 8; | |
unsigned char mask = 1<<7; | |
struct timeval s,f; | |
//gettimeofday(&s,NULL); | |
udelay = RALINK_GPIO_UDELAY; | |
fd = open(GPIO_DEV, O_RDONLY); | |
if (fd < 0) { | |
perror(GPIO_DEV); | |
return -1; | |
} | |
//printf("shift_clk=%d shift_data=%d\n",shift_clk,shift_data); | |
if (0L <= idx && idx < RALINK_GPIO_DATA_LEN/8 && shift_clk >= 0 && shift_data >= 0) | |
req = RALINK_GPIO_WRITE_BYTE | (idx << RALINK_GPIO_DATA_LEN); | |
else { | |
close(fd); | |
printf("gpio_write_byte: index %d out of range\n", idx); | |
} | |
printf("target data:%c\n",c); | |
for(i=0;i<8;i++){ | |
//gettimeofday(&s,NULL); | |
value = 0; | |
tmp = 0; | |
if((c & mask)>0){ value = 1;} | |
else { value = 0;} | |
//printf("target data:%d\n",value); | |
//clk reset(L) 1 | |
tmp = (1<<shift_clk); | |
tmp &= 0xff; | |
if (ioctl(fd, req, tmp) < 0) { perror("ioctl"); close(fd); return -1; } | |
//printf("clk L\n"); | |
//if (ioctl(fd, udelay,delaytime) < 0) { perror("ioctl"); close(fd); return -1;} | |
//usleep(500); //4ms | |
//data set | |
tmp = (1<<shift_clk); | |
tmp |= (value<<shift_data); | |
tmp &= 0xff; | |
if (ioctl(fd, req, tmp) < 0) { perror("ioctl"); close(fd); return -1; } | |
//printf("data set\n"); | |
//usleep(500); | |
//if (ioctl(fd, udelay,delaytime) < 0) { perror("ioctl"); close(fd); return -1;} | |
//clk reset(H) 0 | |
tmp = (value<<shift_data); | |
tmp &= 0xff; | |
if (ioctl(fd, req, tmp) < 0) { perror("ioctl"); close(fd); return -1; } | |
//printf("clk L->H\n"); | |
usleep(500); //4ms | |
//if (ioctl(fd, udelay,delaytime) < 0) { perror("ioctl"); close(fd); return -1;} | |
//clk set(L) 1 | |
tmp = (1<<shift_clk); | |
tmp |= (value<<shift_data); | |
tmp &= 0xff; | |
if (ioctl(fd, req, tmp) < 0) { perror("ioctl"); close(fd); return -1; } | |
//printf("clk H->L\n"); | |
usleep(500); //4ms target sampling time = 500us * 3 = 1500us | |
//if (ioctl(fd, udelay,delaytime) < 0) { perror("ioctl"); close(fd); return -1;} | |
mask = mask >>1; | |
//gettimeofday(&f,NULL); | |
//printf("Total Time=%dms\n",(f.tv_sec-s.tv_sec)*1000+(f.tv_usec-s.tv_usec)/1000); | |
} | |
close(fd); | |
return 0; | |
} |
3.PICマイコンのファーム
変更点
1ms毎にタイマー割り込みを行って、
CLKがH→L(立ち下がり)のタイミングを探す。
更に1ms経過してもLの状態だったら、DATAを読み込む。
main.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* File: main.c | |
* Author: adeno | |
* | |
* Created on 2014/12/07, 13:14 | |
* RT3050F接続のテスト用 | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <xc.h> | |
#include "lcd_lib.h" | |
#include "rcv_lib.h" | |
/* | |
* | |
*/ | |
// CONFIG | |
#pragma config FOSC = INTOSCIO // Oscillator Selection bits (INTOSC oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN) | |
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled) | |
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled) | |
#pragma config MCLRE = ON // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is MCLR) | |
#pragma config BOREN = ON // Brown-out Detect Enable bit (BOD enabled) | |
#pragma config LVP = ON // Low-Voltage Programming Enable bit (RB4/PGM pin has PGM function, low-voltage programming enabled) | |
#pragma config CPD = OFF // Data EE Memory Code Protection bit (Data memory code protection off) | |
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off) | |
#define _XTAL_FREQ 4000000 //delay用に必要(クロック4MHzを指定) | |
#define TMR0_CNT 252 //TMR0カウント値設定 | |
#define CLK_PORT RB5 | |
#define DATA_PORT RB7 | |
#define LCD_ROW 16 | |
#define LCD_COL 2 | |
#define RCV_TIMEOUT 10 //受信タイムアウト 65ms * 10 | |
#define DIST_UART 1 | |
#define DIST_LCD 0 | |
unsigned char dist; //標準出力の出力先 | |
void putch(unsigned char c){ | |
if(dist == DIST_LCD) | |
lcd_data(c); | |
else if(dist == DIST_UART){ | |
while(!TXIF) | |
continue; | |
TXREG = c; | |
} | |
return; | |
} | |
//LCD用表示バッファ | |
volatile char lcd_buf[LCD_ROW+1]; | |
volatile unsigned char lcd_poi = 0; | |
volatile unsigned char lcd_col_poi = 1; //書き込み行数 | |
//SRの | |
unsigned char clk_port_buf; | |
unsigned char sr_timeoutcnt = 0; | |
volatile unsigned char sr_bit = 0; | |
volatile unsigned char sr_buf; | |
int main(int argc, char** argv) { | |
//PORTA 0,1,2,3 LCD DATA | |
//PORTA 7 E | |
//PORTA 6 RS | |
//PORTB 1 RX | |
//PORTB 2 TX | |
//PORTB 4 Debug | |
//PORTB 5 Input(CLK) | |
//PORTB 7 Input(DATA) | |
//PORTB 0,3 外部IO | |
PORTA = 0b00000000; //PORTAの中身をきれいにする | |
TRISA = 0b00000000; //PORTAは 1:入力 0:出力 | |
PORTB = 0b01000101; //PORTBの中身をきれいにする | |
TRISB = 0b10110010; //PORTBは 1:入力 0:出力 | |
//シリアル通信(ボーレート) | |
SYNC = 0; //非同期 | |
BRGH = 1; //高速サンプル | |
SPBRG = 25; //4,000,000Hz / (16 * Baud) - 1 | |
// | |
//シリアル送信 | |
CSRC = 1; | |
TX9 = 0; | |
TXEN = 1; | |
//シリアル受信 | |
SPEN = 1; | |
RX9 = 0; | |
CREN = 1; | |
ADEN = 0; | |
FERR = 0; | |
OERR = 0; | |
RX9D = 0; | |
//TMR0の割り込み初期設定 | |
//0.25us(4MHz)*4*プリスケーラ−256 = 256us | |
//TMR0hは255-3 = 252 | |
OPTION_REG = 0b0111; //プリスケーラ値設定0b0111(=256回) | |
TMR0 = TMR0_CNT; //TMR0カウント値設定 | |
clk_port_buf = 0; | |
sr_timeoutcnt = 0; | |
//LCDの初期化 | |
lcd_init(); | |
//LCDの表示クリア | |
lcd_clear(); | |
dist = DIST_LCD; | |
printf("Hello World!"); | |
//lcd_cmd(0xc0); | |
//lcd_data('a'); | |
//232に出力 | |
dist = DIST_UART; | |
printf("Hello World!\r\n"); | |
//受信バッファの準備 | |
rcv_init(); | |
//LCDバッファの準備 | |
for(lcd_poi = 0; lcd_poi < LCD_ROW; lcd_poi++){ | |
lcd_buf[lcd_poi] = ' '; | |
} | |
lcd_buf[LCD_ROW] = '\0'; | |
lcd_poi = 0; | |
/// | |
lcd_cmd(0xc0); | |
dist = DIST_LCD; | |
printf(lcd_buf); | |
PEIE = 1; | |
INTCONbits.TMR0IE =1; //タイマ割込み許可 | |
RCIE = 1; //RX割り込みをイネーブル | |
INTCONbits.GIE = 1; //全体割込み許可 | |
while(1) { | |
PORTB = 0b00001010; | |
__delay_ms(100); | |
PORTB = 0b00000010; | |
__delay_ms(100); | |
if(getRCVflg() == 1){ | |
//C:コマンド | |
// C:clear 全クリア | |
//I:文字列追加 | |
//N:文字列新規 | |
//if(rcv_buf[0] == 'N' && rcv_buf[1] == ':'){ | |
//以降は文字列 | |
for(lcd_poi = 0; lcd_poi < LCD_ROW; lcd_poi++){ | |
if(read_byte(lcd_poi) != '\n' ){ | |
lcd_buf[lcd_poi] = read_byte(lcd_poi); | |
}else{ | |
break; | |
} | |
} | |
for(;lcd_poi < LCD_ROW; lcd_poi++){ | |
lcd_buf[lcd_poi] = '.'; | |
} | |
lcd_change_col(lcd_col_poi); | |
//lcd_cmd(0xc0); | |
dist = DIST_LCD; | |
printf(lcd_buf); | |
/*}else if(rcv_buf[0] == 'C' && rcv_buf[1] == ':'){ | |
}*/ | |
clearRCVflg(); | |
//RCIE = 1; //RX割り込み再開 | |
} | |
//lcd_cmd(0xc0); | |
} | |
return (EXIT_SUCCESS); | |
} | |
void interrupt isr(void) //割込み関数 | |
{ | |
if (RCIF) | |
{ | |
//rx_data = RCREG; | |
//受信タイムアウトフラグセット | |
//rcv_timeoutflg = 1; | |
//rcv_timeout = RCV_TIMEOUT; | |
unsigned char rcv_wk = ' '; | |
if(FERR) | |
{ | |
rcv_wk = RCREG; | |
//rx_data = 'F'; | |
}else if(OERR) | |
{ | |
CREN = 0; | |
NOP(); | |
CREN = 1; | |
//rx_data = 'O'; | |
}else{ | |
dist = DIST_UART; | |
rcv_byte(RCREG); | |
} | |
}else if(INTCONbits.TMR0IF == 1) { //割込み種がTimer0割込みの場合 | |
INTCONbits.TMR0IF = 0; //Timer0割り込みフラグクリアー | |
TMR0 = TMR0_CNT; //TMR0カウント値設定 | |
sr_timeoutcnt++; | |
if(sr_timeoutcnt > 250 && sr_bit > 0){ | |
sr_bit = 0; | |
sr_timeoutcnt = 0; | |
dist = DIST_UART; | |
printf("TIMEOUT:%c\r\n",sr_buf); | |
} | |
if(CLK_PORT == 0){ | |
if(clk_port_buf == 1){ | |
//clk high | |
//DATA READ | |
clk_port_buf = 2; | |
sr_buf = (sr_buf<<1) | (0x01 & DATA_PORT); | |
sr_bit++; | |
sr_timeoutcnt = 0; | |
if(sr_bit > 7){ | |
sr_bit = 0; | |
dist = DIST_UART; | |
rcv_byte(sr_buf); | |
/*if(DATA_PORT == 1) | |
printf("CLK H->L:DATA H\r\n"); | |
else | |
printf("CLK H->L:DATA L\r\n");*/ | |
} | |
}else if(clk_port_buf > 1){ | |
}else{ | |
clk_port_buf = 1; | |
} | |
}else{ | |
clk_port_buf = 0; | |
} | |
/*if(rcv_timeoutflg == 1){ | |
if(rcv_timeout == 0){ | |
//終了条件3:タイムアウト? | |
//受信データの破棄 | |
rcv_state = RCV_STATE_S1_CMDWAIT; | |
dist = DIST_UART; | |
printf("Rcv Timeout\r\n"); | |
}else{ | |
rcv_timeout--; | |
} | |
}*/ | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include "rcv_lib.h" | |
#include "lcd_lib.h" | |
volatile unsigned char rcv_state = 0; | |
volatile unsigned char rcv_poi = 0; | |
volatile unsigned char rcv_cmd = ' '; | |
volatile unsigned char rcv_buf[RCV_SIZE]; | |
volatile unsigned char rcv_timeoutflg = 0; | |
volatile unsigned char rcv_timeout = 0; | |
volatile unsigned char rcv_full = 0; | |
void rcv_init(){ | |
//受信バッファの準備 | |
for(rcv_poi = 0; rcv_poi < RCV_SIZE; rcv_poi++){ | |
rcv_buf[rcv_poi] = ' '; | |
} | |
rcv_full = 0; | |
} | |
char read_byte(int i){ return rcv_buf[i]; } | |
void clearRCVflg(){ rcv_full = 0; } | |
char getRCVflg(){ return rcv_full; } | |
void rcv_byte(unsigned char c){ | |
if(rcv_full == 1){ | |
printf("BufferFull>%c\r\n",c); | |
}else if(rcv_state == RCV_STATE_S1_CMDWAIT){ | |
rcv_poi = 0; | |
if(c == 'C'){ | |
rcv_timeoutflg = 0; | |
rcv_state = RCV_STATE_S2_CMDWAIT2; | |
//dist = DIST_UART; | |
printf("RCV>C\r\n"); | |
//return "RCV>C\r\n"; | |
}else if(c == 'N'){ | |
rcv_timeoutflg = 0; | |
rcv_state = RCV_STATE_S3_DATAWAIT; | |
//dist = DIST_UART; | |
printf("RCV>N\r\n"); | |
//return "RCV>N\r\n"; | |
}else{ | |
//dist = DIST_UART; | |
printf("Wait for CommandCode. But Rcv>%c\r\n",c); | |
//return "Wait for CommandCode. But Rcv>"+c+"\r\n"; | |
} | |
}else if(rcv_state == RCV_STATE_S2_CMDWAIT2){ | |
//コマンドを一時保存 | |
rcv_timeoutflg = 0; | |
rcv_cmd = c; | |
rcv_state = RCV_STATE_S4_CMDFINWAIT; | |
//dist = DIST_UART; | |
printf("Command RCV>%c\r\n",c); | |
//return "Command RCV>"+c+"\r\n"; | |
}else if(rcv_state == RCV_STATE_S4_CMDFINWAIT){ | |
if(c == '>'){ | |
rcv_timeoutflg = 0; | |
//コマンドの終了条件 | |
if(rcv_cmd == 'C'){ | |
//全クリア | |
lcd_clear(); | |
}else if(rcv_cmd == '1'){ | |
//カーソルを1行目に | |
lcd_change_col(0); | |
}else if(rcv_cmd == '2'){ | |
//カーソルを2行目に | |
lcd_change_col(1); | |
} | |
//dist = DIST_UART; | |
printf("done\r\n"); | |
rcv_state = RCV_STATE_S1_CMDWAIT; | |
//return "done\r\n"; | |
}else{ | |
//dist = DIST_UART; | |
printf("Wait for '>'. But Rcv>%c\r\n",c); | |
//return "Wait for '>'. But Rcv>"+c+"\r\n"; | |
} | |
}else if(rcv_state == RCV_STATE_S3_DATAWAIT){ | |
//dist = DIST_UART; | |
printf("Data RCV>%c poi:%d\r\n",c,rcv_poi); | |
if(c == '\n'){ | |
//終了条件1:\n | |
rcv_buf[rcv_poi] = c; | |
//RCIE = 0; //RX割り込み一時停止 | |
rcv_poi = 0; | |
rcv_timeoutflg = 0; | |
rcv_state = RCV_STATE_S1_CMDWAIT; | |
//rx_flg = 1; | |
rcv_full = 1; | |
//dist = DIST_UART; | |
printf("RCV FIN 1\r\n"); | |
}else if(c == '\r'){ | |
//\rは無視 | |
rcv_timeoutflg = 0; | |
}else{ | |
rcv_timeoutflg = 0; | |
rcv_buf[rcv_poi] = c; | |
rcv_poi++; | |
//終了条件2:バッファがいっぱい | |
if(rcv_poi >= RCV_SIZE){ | |
//RCIE = 0; //RX割り込み一時停止 | |
rcv_poi = 0; | |
rcv_state = RCV_STATE_S1_CMDWAIT; | |
//rx_flg = 1; | |
rcv_full = 1; | |
//dist = DIST_UART; | |
printf("RCV FIN 2\r\n"); | |
} | |
} | |
} | |
} |