[8] 영상의 동기화 맞추기
1) 라즈베리파이의 인터럽트 이용(실패)
아두이노 듀에서 나오는 톱니파 속도를 정해야 한다.
라즈베리에서의 인터럽트가 잘 디텍팅 되지 않는다.
저번에 했던 코드는 100ms라는 느린 펄스파를 감지한거라서 정확하게 갯수와 rising, falling이 검출되었지만 영상을 본격적으로 하기위해서 짠 아두이노 코드에서 나오는 s_p_signal은 rising을 검출하지 못했다. 또는 rising을 검출할 때는 falling을 검출하지 못함.
저번에 된 코드로 테스트 해보니 이 문제는 아두이노에서 나오는 펄스파의 속도가 빨라서 그랬던 거였음.
주기
|
주파수
| |
톱니파에 맞추려면
|
2ms
|
500Hz
|
Rpi 인터럽터에 맞추려면
|
100ms
|
10Hz
|
Rpi 인터럽트에 맞추려면 결국 100ms / 512 samples = 195.3125 u/sample
약 200us 주기로 라즈베리파이에서 ADC 신호를 읽으면 된다.
-인터럽트 동기화 문제
wiringPI 라이브러리에서 제공하는 인터럽트 함수를 썻을 때 문제점이 있었다.
1)인터럽트 설정에서 INIT_EDGE_FALLING으로 설정하더라도 falling edge만 디텍팅 하는 것이아니라 rasing edge까지 디텍팅 되었다.
2)rinsing edge와 falling edge 디텍팅 사이의 시간이 100ms 정도가 있어야 정확한 (사직 한 두개 빠질때도 있음) 디텍팅이 되었다.
3)아누이노의 s_p_signal에서 발생되는 falling edge를 검출하면 바로 원하는 루틴으로 들어가서 데이터를 읽기 시작해야 하는 데 아두이노에서 falling edge가 발생한 후 몇 msec의 오랜 시간이 걸린다음에 인터럽트가 발생했다. .... 그래서 동기화가 안맞았음.
.
채널1(노란색) - 아두이노의 s_p_signal 핀 측정
채널2(파란색) - 라즈베리파이의 인터럽트 측정
=>그래서 인터럽트를 포기함.
2) while 문으로 구현
라즈베리파이의 s_p_signal 핀의 값을 계속 확인하면서 whlie문을 계속 돌다가 아두이노에서 falling edge를 보내면 원하는 루틴으로 들어가도록 하였다.
채널1(노란색) - 아두이노의 s_p_signal 핀 측정
채널2(파란색) - 아두이노의 ADC 톱니파
아두이노에서 나오는 ADC 톱니파을 위 사진에서 초록색깔 모듈인 ADC의 입력에 바로 연결하여 이미지를 만들어 보았다.
그 결과 오른쪽에서 왼쪽으로 갈수록 점점 밝아지는 이미지가 나왔다. 이것은 왼쪽으로 갈 수록 아날로그 값이 선형적으로 커지는 것을 의미하므로 정확하게 이미지를 잘 만들었다는 것을 확인할 수 있었다.
3) 미세 떨림 보정
=>하지만 조그만 흔들림이 있었다.
=>이것은 라즈베리파이가 멀티 프로세싱을 하기때문에 그 때 그때 시작하는 시간이 미세하게 달라지기 때문이다.
=>그래서 단순히 데이터를 읽고 약간의 시간 지연을 위해서 usleep()을 쓰는 것이 아니라 프로그램 내부에서 시간을 측정해서 원하는 시간이 되면 while문을 빠져나가도록 하였다.
=> 그 결과 오실로스코프로 보았을 때, 미세한 떨림이 눈으로는 확인하기 힘들 정도로 줄어들었다.
-convert picture to C code array
원본 이미지와 받은 이미지 비교
arduino due code
//#include "smile.h"
#include "bol.h"
#define ENABLE 0
#define DISABLE 1
#define START 0
#define STOP 1
#define MAXDIGITAL 1024
#define ENABLE_PIN 7
#define DISABLE_PIN 6
#define S_P_SIGNAL_PIN 2
#define OUTPUT_PIN DAC0
volatile int enablePinState;
void makeSawtooth();
void enableISR();
void disableISR();
//void init_img(unsigned char* src);
int raw=0, col=0;
//unsigned char img[256*256] = {0};
void setup(){
// init_img(img);
Serial.begin(9600);
//output
analogWriteResolution(10);
analogWrite(OUTPUT_PIN, 512);
//s_p_signal
pinMode(S_P_SIGNAL_PIN, OUTPUT);
digitalWrite(S_P_SIGNAL_PIN, STOP);
//enable
pinMode(ENABLE_PIN, INPUT_PULLUP);
pinMode(DISABLE_PIN, INPUT_PULLUP);
attachInterrupt(ENABLE_PIN, enableISR, FALLING); //http://m.blog.naver.com/yuyyulee/220310875023
attachInterrupt(DISABLE_PIN, disableISR, RISING);
if(digitalRead(ENABLE_PIN)){
enablePinState=DISABLE;
//enablePinState=ENABLE;
Serial.println("first state is DISABLE");
}else{
enablePinState=ENABLE;
Serial.println("first state is ENABLE");
}
}
void loop(){
//enablePinState=ENABLE;
while(enablePinState == DISABLE){
}
//speed control
// 1) 50, 2) 50
// 3) 10
delay(50); //delay for STOP signal
digitalWrite(S_P_SIGNAL_PIN, START); //falling edge
while(1){
if(enablePinState == DISABLE){
analogWrite(OUTPUT_PIN, 512);
col=0;
raw=0;
break;
}
analogWrite(OUTPUT_PIN, smile[raw*256+col]*4);
//speed control
// 1) 440
// 2) 220
delayMicroseconds(220);
col++;
if(col == 256){
col=0;
break;
}
}
digitalWrite(S_P_SIGNAL_PIN, STOP); //rising edge
analogWrite(OUTPUT_PIN, 512);
raw++;
if(raw==256){
raw = 0;
}
}
void enableISR(){
enablePinState = ENABLE;
Serial.println("enable");
}
void disableISR(){
enablePinState = DISABLE;
//enablePinState = ENABLE;
Serial.println("disable");
}
/*
void init_img(unsigned char* src){
int i=0, j=0;
for(i=0; i<256; i++){
for(j=0; j<256; j++){
src[i*256+j] = j;
}
}
}
*/
|
capcher.h
#ifndef CAPCHERIMAGE_H
#define CAPCHERIMAGE_H
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <wiringPi.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <QtCore>
#include <QMutex>
#include <QThread>
#include "myspi.h"
#include "readdetector.h"
#include <sys/time.h>
#include <unistd.h>
#include "jpeglib.h"
//PIN NUMBER
#define S_P_SIGNAL_PIN 7 //pysical 7
#define SYNCHRONIZATION_PIN 25 //pysical 37
//set value
#define FRAME_NUMBER 1
#define MAXROW 512
#define MAXCOL 1000
#define DELAYSECOND 10
#define START 0
#define STOP 1
#define ERROR -1
//tread state
#define TREAD_START 0
#define TREAD_END 1
#define TREAD_RUNNING 2
#define TREAD_PAUSE 3
#define TREAD_RESUME 4
#define DISPLAY_IMAGE 5
volatile static int s_p_signal = STOP;
class CapcherImage : public readDetector
{
Q_OBJECT
public:
QMutex mutex;
volatile unsigned int* gpio;
CapcherImage(){readDetector::Init_8bit_GPIO(); m_stop = false; m_pause = false;}
void readOneFrame(unsigned char* oneFrame);
void init_Interrupt();
void arduinoSAWTOOTHWAVE(int command);
void run();
void pause() { m_pause = true; }
void resume() { m_pause = false; m_pauseCondition.wakeAll();}
int makeJPEG(unsigned char* oneFrame);
private:
bool m_stop;
bool m_pause;
QWaitCondition m_pauseCondition;
signals:
void state(int treadState);
void imageMakingProgress(int raw);
};
void interruptISR(void) ;
#endif // CAPCHERIMAGE_H
|
capcher.cpp
#include "capcherimage.h"
void CapcherImage::run(){
unsigned char img[256*256]={0};
qDebug("Image Thread start!"); //"start!!"
emit state(TREAD_START);
while(1)
{
if (m_pause)
{
emit state(TREAD_PAUSE); //"complete!!"
m_pauseCondition.wait(&mutex);
emit state(TREAD_RESUME);//"start!!"
}
//running code
arduinoSAWTOOTHWAVE(ENABLE);
readOneFrame(img);
arduinoSAWTOOTHWAVE(DISABLE);
emit state(TREAD_RUNNING); //"image make..."
if(makeJPEG(img) == ERROR){
m_pause = TRUE;
qDebug("make image error!!");
continue;
}
emit state(DISPLAY_IMAGE);
//running code end
m_pause = TRUE;
}
emit state(TREAD_END); //"complete!!"
qDebug("Image Thread stop!");
}
void CapcherImage::arduinoSAWTOOTHWAVE(int command){
if(command == ENABLE){
digitalWrite(ARDUINO_ENABLE_PIN, ENABLE);
}else if(command == DISABLE){
digitalWrite(ARDUINO_ENABLE_PIN, DISABLE);
}
}
void CapcherImage::readOneFrame(unsigned char *oneFrame){
int raw = 0, col=0;
long int start_time;
long int time_difference;
struct timespec gettime_now;
int percent = 0;
int lock = ON;
long int in_start_time;
long int in_time_difference;
struct timespec in_gettime_now;
s_p_signal=STOP;
imageMakingProgress(percent);
gpio_8bit_usage(ENABLE);
//while start
while(1){
//measure strat time
clock_gettime(CLOCK_REALTIME, &gettime_now);
start_time = gettime_now.tv_nsec;
if(digitalRead(S_P_SIGNAL_PIN) == STOP){
lock = OFF;
}
if(digitalRead(S_P_SIGNAL_PIN) == START && lock == OFF){
lock = ON;
/*
//measure strat time
clock_gettime(CLOCK_REALTIME, &gettime_now);
start_time = gettime_now.tv_nsec;
*/
//speed control
// 1) 500
// 2) 30
//usleep(30);
//mearsure end time
do{
clock_gettime(CLOCK_REALTIME, &gettime_now);
time_difference = gettime_now.tv_nsec - start_time;
if(time_difference<0)
time_difference += 1000000000;
//qDebug("msec : %lf", time_difference/1000000.0);
}while(time_difference < 100000);
//synchronization test
digitalWrite(SYNCHRONIZATION_PIN, START);
while(1){
//measure strat time
clock_gettime(CLOCK_REALTIME, &in_gettime_now);
in_start_time = in_gettime_now.tv_nsec;
//read
oneFrame[raw*256 + col] = Read_8bit_GPIO();
col++;
//speed control
// 1) 410
// 2) 160
//usleep(160);
if(col == 256){
//synchronization test
digitalWrite(SYNCHRONIZATION_PIN, STOP);
/*
//mearsure end time
clock_gettime(CLOCK_REALTIME, &gettime_now);
time_difference = gettime_now.tv_nsec - start_time;
if(time_difference<0)
time_difference += 1000000000;
qDebug("msec : %lf", time_difference/1000000.0);
*/
col =0;
raw++;
if((raw+4) % 26 == 0){
int percent = (raw+4)/26;
imageMakingProgress(percent); //take 50 usec
}
break;
}
//mearsure end time
do{
clock_gettime(CLOCK_REALTIME, &in_gettime_now);
in_time_difference = in_gettime_now.tv_nsec - in_start_time;
if(in_time_difference<0)
in_time_difference += 1000000000;
//qDebug("msec : %lf", in_time_difference/1000000.0);
}while(in_time_difference < 234000);
}
}
if(raw == 256){
break;
}
}
//while end
gpio_8bit_usage(DISABLE);
}
int CapcherImage::makeJPEG(unsigned char *oneFrame){
const int image_height=256, image_width=256;
const char *filename = "result.jpeg";
//initialize image array
/*
for(int i=0; i<256*256; i++){
oneFrame[i] = 200;
}*/
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE *outfile;
JSAMPROW row_pointer[1];
int row_stride;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
outfile = fopen(filename, "wb");
if(outfile == NULL){
fprintf(stderr, "can't open %s\n", filename);
exit(1);
}
jpeg_stdio_dest(&cinfo, outfile);
cinfo.image_width = image_width;
cinfo.image_height = image_height;
cinfo.input_components = 1;
cinfo.in_color_space = JCS_GRAYSCALE;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, 75, TRUE);
jpeg_start_compress(&cinfo, TRUE);
row_stride = image_width * 1;
while(cinfo.next_scanline < cinfo.image_height){
row_pointer[0] = &oneFrame[cinfo.next_scanline * row_stride];
(void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
jpeg_finish_compress(&cinfo);
fclose(outfile);
qDebug("image file is created");
return 0;
}
void CapcherImage::init_Interrupt(){
pinMode(S_P_SIGNAL_PIN, INPUT);
pullUpDnControl(S_P_SIGNAL_PIN, PUD_UP);
pinMode(SYNCHRONIZATION_PIN, OUTPUT);
/*
if ( wiringPiISR (S_P_SIGNAL_PIN, INT_EDGE_FALLING, &interruptISR) < 0 ) {
fprintf (stderr, "Unable to setup ISR: %s\n", strerror (errno));
exit(-1);
}
*/
}
void interruptISR(void) {
char val = digitalRead(S_P_SIGNAL_PIN);
if(val == LOW){
s_p_signal = START;
//qDebug("falling edge detected");
}
else if(val == HIGH){
s_p_signal = STOP;
//qDebug("rising edge detected");
}
}
|
프로그램 수행 시간 측정
-clock_gettime()
채널1(노란색) - 라즈베리파이의 enable 핀 측정
채널2(파란색) - 아두이노의 s_p_signal 핀 측정