void gammaEdit(void){ uint16_t x,y,z; setColor(rgb565); setRes(qqvga); #ifdef MT9D111 MT9D111Refresh(); #endif tft_paintScreenBlack(); #ifdef MT9D111 return; #else do{ getPoint(&x,&y,&z); tft_setOrientation(1); #ifdef ov7670 wrReg(REG_COM13, COM13_UVSAT|COM13_RSVD); #elif defined ov7740 wrReg(ISP_CTRL00,rdReg(ISP_CTRL00)&(~ISP_CTRL00_gamma)); #endif capImgqqvga(160); #ifdef ov7670 wrReg(REG_COM13, COM13_GAMMA|COM13_UVSAT|COM13_RSVD); #elif defined ov7740 wrReg(ISP_CTRL00,rdReg(ISP_CTRL00)|ISP_CTRL00_gamma); #endif capImgqqvga(0); tft_setDisplayDirect(DOWN2UP); redrawGraph(); }while(z<10); setRes(qvga); #endif }
int main(void){ cli();//disable interrupts /* Setup the 8mhz PWM clock * This will be on pin 11*/ DDRB|=(1<<3);//pin 11 ASSR &= ~(_BV(EXCLK) | _BV(AS2)); TCCR2A=(1<<COM2A0)|(1<<WGM21)|(1<<WGM20); TCCR2B=(1<<WGM22)|(1<<CS20); OCR2A=0;//(F_CPU)/(2*(X+1)) DDRC&=~15;//low d0-d3 camera DDRD&=~252;//d7-d4 and interrupt pins _delay_ms(3000); //set up twi for 100khz TWSR&=~3;//disable prescaler for TWI TWBR=72;//set to 100khz //enable serial UBRR0H=0; UBRR0L=1;//0 = 2M baud rate. 1 = 1M baud. 3 = 0.5M. 7 = 250k 207 is 9600 baud rate. UCSR0A|=2;//double speed aysnc UCSR0B = (1<<RXEN0)|(1<<TXEN0);//Enable receiver and transmitter UCSR0C=6;//async 1 stop bit 8bit char no parity bits camInit(); #ifdef useVga setRes(VGA); setColorSpace(BAYER_RGB); wrReg(0x11,25); #elif defined(useQvga) setRes(QVGA); setColorSpace(YUV422); wrReg(0x11,12); #else setRes(QQVGA); setColorSpace(YUV422); wrReg(0x11,3); #endif /* If you are not sure what value to use here for the divider (register 0x11) * Values I have found to work raw vga 25 qqvga yuv422 12 qvga yuv422 21 * run the commented out test below and pick the smallest value that gets a correct image */ while (1){ /* captureImg operates in bytes not pixels in some cases pixels are two bytes per pixel * So for the width (if you were reading 640x480) you would put 1280 if you are reading yuv422 or rgb565 */ /*uint8_t x=63;//Uncomment this block to test divider settings note the other line you need to uncomment do{ wrReg(0x11,x); _delay_ms(1000);*/ #ifdef useVga captureImg(640,480); #elif defined(useQvga) captureImg(320*2,240); #else captureImg(160*2,120); #endif //}while(--x);//Uncomment this line to test divider settings } }
void setRes(enum RESOLUTION res){ switch(res){ case VGA: wrReg(REG_COM3,0); // REG_COM3 wrSensorRegs8_8(vga_ov7670); break; case QVGA: wrReg(REG_COM3,4); // REG_COM3 enable scaling wrSensorRegs8_8(qvga_ov7670); break; case QQVGA: wrReg(REG_COM3,4); // REG_COM3 enable scaling wrSensorRegs8_8(qqvga_ov7670); break; } }
void setColor(uint8_t color){ #ifdef MT9D111 wrReg16(0xF0,1); #endif switch(color){ case yuv422: #ifdef MT9D111 wrReg16(0xC6,(1<<15)|(1<<13)|(7<<8)|125); wrReg16(0xC8,0); wrReg16(0xC6,(1<<15)|(1<<13)|(7<<8)|126); wrReg16(0xC8,0); #else wrSensorRegs8_8(yuv422_ov7670); #endif break; case rgb565: #ifdef MT9D111 wrReg16(0xC6,(1<<15)|(1<<13)|(7<<8)|125); wrReg16(0xC8,(1<<5)); wrReg16(0xC6,(1<<15)|(1<<13)|(7<<8)|126); wrReg16(0xC8,(1<<5)); #else wrSensorRegs8_8(rgb565_ov7670); {uint8_t temp=rdReg(0x11); _delay_ms(1); wrReg(0x11,temp);}//accorind to the linux kernel driver rgb565 PCLK needs re-writting #endif break; #ifndef MT9D111 case bayerRGB: wrSensorRegs8_8(bayerRGB_ov7670); break; #endif } }
/** Tone step of tone generator. \param pCh - handle to a VINETIC channel structure \param pTone - internal simple tone table entry \return none \remarks */ IFX_LOCAL TAPI_CMPLX_TONE_STATE TG_ToneStep(VINETIC_CHANNEL* pCh, IFX_TAPI_TONE_SIMPLE_t const *pTone, IFX_uint8_t res) { if (pCh->nToneStep > IFX_TAPI_TONE_STEPS_MAX || pTone->cadence[pCh->nToneStep] == 0) { pCh->nToneStep = 0; if (pTone->loop != 0) { pCh->nTone_Cnt--; if (pCh->nTone_Cnt == 0) { DSCR.value &= ~(DSCR_COR8 | DSCR_PTG | DSCR_TG1_EN | DSCR_TG2_EN); wrReg (pCh, DSCR_REG); return TAPI_CT_DEACTIVATED; } } if (pTone->loop == 0 || pTone->loop > 1) { if (pTone->pause > 0) { /* set tone timer */ TAPI_SetTime_Timer (pCh->pToneRes[res].Tone_Timer, pTone->pause, IFX_FALSE, IFX_TRUE); return TAPI_CT_ACTIVE; } } } DSCR.value &= ~(DSCR_COR8 | DSCR_PTG | DSCR_TG1_EN | DSCR_TG2_EN); if (pTone->frequencies[pCh->nToneStep] & IFX_TAPI_TONE_FREQA) /* data to start tone generator 1 */ DSCR.value |= (DSCR_COR8 | DSCR_PTG | DSCR_TG1_EN); if (pTone->frequencies[pCh->nToneStep] & IFX_TAPI_TONE_FREQB) DSCR.value |= DSCR_TG2_EN; /* call target function to set tone generator(s) */ wrReg (pCh, DSCR_REG); /* set tone timer */ TAPI_SetTime_Timer (pCh->pToneRes[res].Tone_Timer, pTone->cadence[pCh->nToneStep], IFX_FALSE, IFX_TRUE); pCh->nToneStep++; return TAPI_CT_ACTIVE; }
void wrSensorRegs8_8(const struct regval_list reglist[]){ uint8_t reg_addr,reg_val; const struct regval_list *next = reglist; while ((reg_addr != 0xff) | (reg_val != 0xff)){ reg_addr = pgm_read_byte(&next->reg_num); reg_val = pgm_read_byte(&next->value); wrReg(reg_addr, reg_val); next++; } }
void setRes(uint8_t res){ switch(res){ #ifdef MT9D111 case svga: setMT9D111res(800,600); break; #endif case vga: //wrReg(0x11,2);//divider #ifdef ov7740 scalingToggle(0); #elif defined MT9D111 //wrSensorRegs8_16(MT9D111_VGA); setMT9D111res(640,480); #else wrReg(REG_COM3,0); // REG_COM3 wrSensorRegs8_8(vga_ov7670); #endif break; case qvga: #ifdef ov7740 scalingToggle(1); #elif defined MT9D111 //wrSensorRegs8_16(MT9D111_QVGA); setMT9D111res(320,240); #else wrReg(0x11,1);//divider wrReg(REG_COM3,4); // REG_COM3 enable scaling wrSensorRegs8_8(qvga_ov7670); #endif break; case qqvga: #ifdef ov7740 scalingToggle(1); #elif defined MT9D111 setMT9D111res(160,120); #else wrReg(0x11,0);//divider wrReg(REG_COM3,4); // REG_COM3 enable scaling wrSensorRegs8_8(qqvga_ov7670); #endif } }
static void wrSensorRegs8_8(const struct regval_list reglist[]){ const struct regval_list *next = reglist; for(;;){ uint8_t reg_addr = pgm_read_byte(&next->reg_num); uint8_t reg_val = pgm_read_byte(&next->value); if((reg_addr==255)&&(reg_val==255)) break; wrReg(reg_addr, reg_val); next++; } }
void setColorSpace(enum COLORSPACE color){ switch(color){ case YUV422: wrSensorRegs8_8(yuv422_ov7670); break; case RGB565: wrSensorRegs8_8(rgb565_ov7670); {uint8_t temp=rdReg(0x11); _delay_ms(1); wrReg(0x11,temp);}//according to the Linux kernel driver rgb565 PCLK needs rewriting break; case BAYER_RGB: wrSensorRegs8_8(bayerRGB_ov7670); break; } }
/** Play a local tone on one or both tone generators. \param pCh - handle to a VINETIC channel structure \param vers - chip revision \param freqA - frequency A in mHz \param freqB - frequency B in mHz, or zero if not applicable \return IFX_SUCCESS or IFX_ERROR */ IFX_int32_t Tone_TG_SetCoeff (VINETIC_CHANNEL* pCh, IFX_uint8_t vers, IFX_int32_t freqA, IFX_int32_t freqB) { IFX_int32_t ret; #ifdef VIN_V14_SUPPORT COEFF_TAB_ENTRY tab_entry; IFX_uint16_t pData [4] = {0}; #endif /* VIN_V14_SUPPORT */ switch (vers) { #ifdef VIN_V14_SUPPORT case VINETIC_V1x: tab_entry.quantVal = freqA; /* now get the coefficient from global frequency / coefficient table. result is returned in pEntry */ ret = Cram_getUnitCoef (IOSET, &tab_entry, (COEFF_TAB_ENTRY *) VINETIC_CRAM_TGFreqQuantVal_Table); if (ret != IFX_SUCCESS) return IFX_ERROR; pData[0] = LOWWORD ((IFX_uint32_t)tab_entry.CRAMcoeff); pData[1] = HIGHWORD ((IFX_uint32_t)tab_entry.CRAMcoeff); /* c1 = tab_entry.CRAMcoeff; */ if (freqB) { tab_entry.quantVal = (IFX_int32_t)freqB; ret = Cram_getUnitCoef (IOSET, &tab_entry, (COEFF_TAB_ENTRY *) VINETIC_CRAM_TGFreqQuantVal_Table); if (ret != IFX_SUCCESS) return IFX_ERROR; pData[2] = LOWWORD ((IFX_uint32_t)tab_entry.CRAMcoeff); pData[3] = HIGHWORD ((IFX_uint32_t)tab_entry.CRAMcoeff); /* c2 = tab_entry.CRAMcoeff; */ ret = RegWrite (pCh->pParent, CMD1_COP | (pCh->nChannel - 1), pData, 4, CRAM_PTG1); } else { ret = RegWrite (pCh->pParent, CMD1_COP | (pCh->nChannel - 1), pData, 2, CRAM_PTG1); } break; #endif /* VIN_V14_SUPPORT */ #ifdef VIN_V21_SUPPORT case VINETIC_V2x: /* set the frequency for the first TG */ ret = setRegVal (pCh, TG1F_REG, freqA); if (ret == IFX_SUCCESS) ret = wrReg (pCh, TG1F_REG); /* set the frequency for the second TG */ if ((ret == IFX_SUCCESS) && (freqB != 0)) { ret = setRegVal (pCh, TG2F_REG, freqB); if (ret == IFX_SUCCESS) ret = wrReg (pCh, TG2F_REG); } break; #endif /* VIN_V21_SUPPORT */ default: return IFX_ERROR; } if (ret == IFX_SUCCESS) { DSCR.value &= ~(DSCR_TG2_EN); /* data to start tone generator 1 */ DSCR.value |= (DSCR_COR8 | DSCR_PTG | DSCR_TG1_EN); if (freqB) DSCR.value |= DSCR_TG2_EN; /* call target function to set tone generator(s) */ ret = wrReg (pCh, DSCR_REG); } return ret; }
void menu(void) { uint16_t x,y,z; while (1) { switch (selection((const char**)menu_table,10)) { case 0: #ifdef MT9D111 setRes(QVGA); setColor(RGB565); MT9D111Refresh(); editRegs(0); #else setColor(RGB565); setRes(QVGA); editRegs(); #endif break; case 1: #ifdef MT9D111 setRes(QVGA); setColor(RGB565); MT9D111Refresh(); editRegs(1); #else #ifdef ov7740 setmatrix(selection((const char**)maxtrix_table,2)); #else setmatrix(selection((const char**)maxtrix_table,3)); #endif tft_setOrientation(1); capImg(); tft_setDisplayDirect(DOWN2UP); #endif break; case 2: #ifdef ov7670 initCam(0); #else initCam(); #endif break; #ifndef MT9D111 case 3: //compare matrices tft_setOrientation(1); do { getPoint(&x,&y,&z); uint8_t a; #ifdef ov7670 for (a=0; a<3; a++) { #elif defined ov7740 for (a=0; a<2; a++) { #endif setmatrix(a); capImg(); } } while (z < 10); tft_setDisplayDirect(DOWN2UP); break; #endif case 4: setColor(RGB565); setRes(QQVGA); #ifdef MT9D111 MT9D111Refresh(); #endif do { getPoint(&x,&y,&z); tft_setOrientation(1); capImgqqvga(160); tft_setDisplayDirect(DOWN2UP); } while(z<10); setRes(QVGA); break; case 5: #ifdef ov7670 setColor(RGB565); #endif gammaEdit(); break; case 6: //File browser //start by listing files #ifdef haveSDcard browserSD(); #else tft_drawStringP(PSTR("No SD card"),16,320,3,WHITE); _delay_ms(666); #endif break; case 7: #ifdef ov7670 { uint8_t pick=selection((const char**)wb_table,7);//registers from http://thinksmallthings.wordpress.com/2012/10/25/white-balance-control-with-ov7670/ if(pick==1||pick==2) { wrReg(0x13, 0xE7); wrReg(0x6F, 0x9E|(pick&1)); } else { wrReg(0x13, 0xE5); switch(pick) { case 2: wrReg(0x01, 0x5A); wrReg(0x02, 0x5C); break; case 3: wrReg(0x01, 0x58); wrReg(0x02, 0x60); break; case 4: wrReg(0x01, 0x84); wrReg(0x02, 0x4C); break; case 5: wrReg(0x01, 0x96); wrReg(0x02, 0x40); break; } } tft_setOrientation(1); setRes(QVGA); setColor(RGB565); capImg(); tft_setDisplayDirect(DOWN2UP); } #endif break; case 8: #ifdef ov7670 wrReg(0x1e,rdReg(0x1e)&(~(1<<5))&(~(1<<4))); #endif { #ifdef MT9D111 uint8_t reso=selection((const char**)res_tab,4); #else uint8_t reso=selection((const char**)res_tab,3); #endif #ifdef MT9D111 wrReg16(0xF0,2);//page 2 wrReg16(0x0D,0); setColor(YUV422); #endif switch(reso) { case 0: #ifdef ov7670 wrReg(REG_COM7, COM7_BAYER); // BGBGBG... GRGRGR... #elif defined MT9D111 //setup jpeg MT9D111JPegCapture(); #endif break; case 1: #ifdef MT9D111 setRes(SVGA); #else setRes(QVGA); setColor(YUV422); #endif break; #ifdef MT9D111 case 2: setRes(QVGA); break; #endif default: goto theEnd; break; } #ifdef ov7670 _delay_ms(200); if(reso) wrReg(0x11,1); else wrReg(0x11,2); #endif tft_setOrientation(1); do { #ifdef MT9D111 switch(reso) { case 0: { uint32_t jpgSize=capJpeg(); serialWrB('R'); serialWrB('D'); serialWrB('Y'); uint16_t w; uint8_t h=0; serialWrB(jpgSize&255); serialWrB(jpgSize>>8); serialWrB(jpgSize>>16); serialWrB(jpgSize>>24); while(jpgSize) { if(jpgSize>=640) { for (w=0; w<320; ++w) { tft_setXY(h,w); BSend(); } ++h; jpgSize-=640; } else { for(w=0; w<jpgSize/2; ++w) { tft_setXY(h,w); BSend(); } if(jpgSize&1) { tft_setXY(h,w); uint16_t res=tft_readRegister(0x22); serialWrB(res>>8); } jpgSize=0; } } } break; case 1: capImgPC(); break; case 2: capImgPCqvga(); break; } #else if(reso) capImgPCqvga(); else capImgPC(); #endif getPoint(&x,&y,&z); } while(z<10); theEnd: tft_setDisplayDirect(DOWN2UP); } break; case 9: switch(selection((const char**)menu_tablep2,3)) { case 0: { tft_drawImage_P(exit_icon,32,32,0,0); uint16_t x1,y1; do { getPoint(&x,&y,&z); } while(z<10); if((y<=32)&&(x<=32)) break; tft_fillCircle(x,y,4,WHITE); while(1) { x1=x; y1=y; do { getPoint(&x,&y,&z); } while(z<10); tft_fillRectangle(224,320,16,36,BLACK); tft_fillCircle(x1,y1,4,BLACK); tft_fillCircle(x,y,4,WHITE); if((y<=32)&&(x<=32)) break; char temp[6]; utoa(x,temp,10); tft_drawString(temp,224,320,1,WHITE); utoa(y,temp,10); tft_drawString(temp,232,320,1,WHITE); } } break; case 1: //time lapse #ifdef MT9D111 //MT9D111Refresh(); //Since This is a time lapse we want to be in "video" mode MT9D111JPegCapture(); /*do{ _delay_ms(10); wrReg16(0xC6,(1<<15)|(1<<13)|(1<<8)|4); }while(rdReg16(0xC8)<4); waitStateMT9D111(3);*/ #endif #ifdef haveSDcard { char buf[24]; uint16_t imgc=0; tft_setOrientation(1); do { FIL Fo; #ifdef MT9D111 uint32_t jpgSize=capJpeg(); #else capImg(); #endif utoa(imgc,buf,10); #ifdef MT9D111 strcat(buf,".JPG"); #else strcat(buf,".RAW"); #endif f_open(&Fo,buf,FA_WRITE|FA_CREATE_ALWAYS); ++imgc; UINT written; uint16_t w; uint8_t h; uint16_t cpybuf[320]; #ifdef MT9D111 h=0; uint8_t * cpyptr=cpybuf; for(w=0; w<619; ++w) *cpyptr++=pgm_read_byte_near(jpegHeader+w); f_write(&Fo,cpybuf,619,&written); while(jpgSize) { if(jpgSize>=640) { for (w=0; w<320; ++w) { tft_setXY(h,w); cpybuf[w]=__builtin_bswap16(tft_readRegister(0x22));//Either bytes need to be swapped or a byte is being missed } f_write(&Fo,cpybuf,640,&written); ++h; jpgSize-=640; } else { for(w=0; w<jpgSize/2; ++w) { tft_setXY(h,w); cpybuf[w]=__builtin_bswap16(tft_readRegister(0x22)); } f_write(&Fo,cpybuf,jpgSize,&written); if(jpgSize&1) { tft_setXY(h,w); cpybuf[w]=tft_readRegister(0x22); f_write(&Fo,&cpybuf[w],1,&written); } jpgSize=0; } } cpybuf[0]=0xFFD9; f_write(&Fo,cpybuf,2,&written); #else for (h=0; h<240; ++h) { for (w=0; w<320; ++w) { tft_setXY(h,w); cpybuf[w]=tft_readRegister(0x22); } f_write(&Fo,cpybuf,640,&written); } #endif f_close(&Fo); getPoint(&x,&y,&z); } while(z<10); tft_setDisplayDirect(DOWN2UP); #ifdef MT9D111 MT9D111DoPreview(); #endif } #else tft_drawStringP(PSTR("No SD card"),16,320,3,WHITE); _delay_ms(666); #endif break; case 2: //previous page break; } break; } } }
static void setmatrix(uint8_t id) { switch (id) { case 0: #ifdef ov7670 wrReg(MTX1,0x80); wrReg(MTX2,0x80); wrReg(MTX3,0x00); wrReg(MTX4,0x22); wrReg(MTX5,0x5e); wrReg(MTX6,0x80); wrReg(MTXS,0x9e); #elif defined ov7740 wrReg(ISP_CTRL01,rdReg(ISP_CTRL01)&(~ISP_CTRL01_CMX_enable)); #endif break; case 1: #ifdef ov7670 wrReg(MTX1,0x40); wrReg(MTX2,0x34); wrReg(MTX3,0x0c); wrReg(MTX4,0x17); wrReg(MTX5,0x29); wrReg(MTX6,0x40); wrReg(MTXS,0x1A); #elif defined ov7740 wrReg(ISP_CTRL01,rdReg(ISP_CTRL01)|ISP_CTRL01_CMX_enable); #endif break; #ifdef ov7670 case 2: wrReg(MTX1,0xB3); wrReg(MTX2,0xB3); wrReg(MTX3,0x0); wrReg(MTX4,0x3D); wrReg(MTX5,0xA7); wrReg(MTX6,0xE4); wrReg(MTXS,0x9E); break; #endif } }
void camInit(void){ wrReg(0x12, 0x80);//Reset the camera. _delay_ms(100); wrSensorRegs8_8(ov7670_default_regs); wrReg(REG_COM10,32);//PCLK does not toggle on HBLANK. }
void initCam(void) #endif { #ifdef MT9D111 //_delay_ms(1000); //wrSensorRegs8_16P(MT9D111_init); //_delay_ms(1000); //wrSensorRegs8_16(MT9D111_QVGA); //wrSensorRegs8_16(MT9D111_RGB565); //wrSensorRegs8_16(default_size_a_list); //Start off with a soft reset wrReg16(0xF0,1);//Set to page 1 wrReg16(0xC3,0x0501); wrReg16(0xF0,0); wrReg16(0x0D,0x0021); wrReg16(0x0D,0); _delay_ms(100);//Cannot use i2c for 24 camera cylces this should be way over that. waitStateMT9D111(3); //wrReg16(0xF0,0);//Set to page 0 //wrReg16(0x15,(1<<7)|3); wrReg16(0xF0,1);//Set to page 1 //Poll camera until it is ready /*wrReg16(0xC6,(1<<13)|(7<<8)|25);//Row speed wrReg16(0xC8,3);*/ wrReg16(0xC6,(1<<15)|(1<<13)|(2<<8)|14);//increase maximum intergration time wrReg16(0xc8,128); /*wrReg16(0xC6,(1<<15)|(1<<13)|(2<<8)|16);//increase maximum virtual gain wrReg16(0xc8,232); wrReg16(0xC6,(1<<15)|(1<<13)|(2<<8)|24);//increase maximum gain wrReg16(0xc8,224);*/ wrReg16(0xC6,(1<<13)|(2<<8)|20);//increase maximum pre-lc digital gain wrReg16(0xc8,256); /*wrReg16(0xC6,(1<<15)|(1<<13)|(7<<8)|67);//gamma contex A wrReg16(0xC8,2); wrReg16(0xC6,(1<<15)|(1<<13)|(7<<8)|68);//gamma B wrReg16(0xC8,2);*/ //MT9D111Refresh(); //_delay_ms(1000); wrReg16(0xC6,(1<<13)|(7<<8)|107);//Fifo context A wrReg16(0xC8,0); wrReg16(0xC6,(1<<13)|(7<<8)|114);//Fifo context B wrReg16(0xC8,0); MT9D111Refresh(); //_delay_ms(1000); #elif defined ov7740 wrReg(0x12,rdReg(0x12)|1);//RGB mode wrReg(0x11,16);//divider wrReg(0x55,0);//disable double wrReg(0x83,rdReg(0x83)|(1<<2));//RAW 8 #elif defined ov7670 wrReg(0x12, 0x80); _delay_ms(100); if(bayerUse==2){ wrSensorRegs8_8(OV7670_QVGA); } else if(bayerUse==1){ uint16_t n; for(n = 0; n < sizeof(reg_init_data);n+=2) wrReg(pgm_read_byte_near(reg_init_data+n), pgm_read_byte_near(reg_init_data+n+1)); } else wrSensorRegs8_8(ov7670_default_regs); if(bayerUse!=2) wrReg(0x1e,rdReg(0x1e)|(1<<5));//hflip if(bayerUse==1) wrReg(REG_COM10,48); else wrReg(REG_COM10,32);//pclk does not toggle on HBLANK wrReg(REG_COM11,98); #else #error "No sensor selected" #endif }
void scalingToggle(uint8_t use){ if(use) wrReg(ISP_CTRL02,rdReg(ISP_CTRL02)|(1<<4)|(1<<5)); else wrReg(ISP_CTRL02,rdReg(ISP_CTRL02)&(~((1<<4)|(1<<5)))); }