📄 cc303.c
字号:
// define sequencer fields to be ORed with 10-bit step duration in (pixel) clock periods.// Actual duration is longer by two 20MHz clock periods. (0->100ns, 1->150ns, etc.)#define sfld_astop 0x00400 // turn sequencer off#define sfld_genIn 0x00800 // generate interrupt (at the beginning of this step)#define sfld_gtNxt 0x01000 // increment address when the duration counter will expire (0 - forever repeat current step)#define sfld_xen_pend 0x02000 // enable external trigger to branch sequencer to the address 6'h00 AT THE END of the current step. (see NOTE1)#define sfld_xen_imm 0x04000 // enable external trigger to branch sequencer to the address 6'h00 IMMEDIATELY (see NOTE1)#define sfld_xt_rst 0x06000 // reset 'was external trigger" flag, enable software modification of the sequencer address.#define sfld_GATE 0x08000 // turn ON xternal shutter device (i.e. MCP) (see NOTE2)#define sfld_ARO 0x10000 // send ARO pulse to zr32112 (see NOTE2)#define sfld_ARST 0x20000 // send (inverted, active-low) ARO pulse to zr32112 (see NOTE2)// NOTE1: if both bits sfld_xen_pend and sfld_xen_imm are set - reset 'was external trigger" flag,// enable software modification of the sequencer address.// NOTE2: These bits are combined with other (non-sequencer) bits in DCR before being output#define MAXEXPOSURE 60000 //60 sec, in 1ms incrementsstatic volatile int camSeqState;/*#define CAMSEQ_OFF 0 // off#define CAMSEQ_PREERASE 1 // preerasing#define CAMSEQ_WAITTRIG 2 // waiting for trigger#define CAMSEQ_TRIGGERED 3 // triggered#define CAMSEQ_STILLDMA 4 // acquiring still image (DMA running)#define CAMSEQ_STILLGOT 5 // still picture acquired#define CAMSEQ_VIDEOON 6 // video mode just started, not ready for picture acquisition yet#define CAMSEQ_VIDEORDY 7 // video mode passed first VACT pulse, ready to acquire a new picture#define CAMSEQ_VIDEOWAIT 8 // video mode - waiting for external trigger (not implemented yet)#define CAMSEQ_VIDEODMA 9 // video mode - acquiring picture#define CAMSEQ_VIDEOGOT 10 // video mode - picture got*/#define PREERASE 5static volatile int camSeqCount; // Value= exposure time in msec (left)static volatile int camSeqPreCount; // Value= preerase cyclesstatic int getCamSeqState(void) {return camSeqState;}static int getCamSeqCount(void) {return camSeqCount;}//static int getCamSeqPreCount(void) {return camSeqPreCount;}static void setCamSeqState(int v) {camSeqState=v;}static void setCamSeqCount(int v) {camSeqCount=v;}static void setCamSeqPreCount(int v) {camSeqPreCount=v;}static void initCamIRQs(void){ int camIRQVectors[8]={0x24,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a}; int i;// setup cam-sequencer data// seems to be that the best way is to keep reset always on before the exposure - remove sequencing later port_csp0_addr[CCAM_WA_WWA]= 0x20; // sequencer start(or anything but 0 - reserved for trigger) port_csp0_addr[CCAM_WA_SEQWRD]= sfld_xen_imm | sfld_ARST | sfld_gtNxt ;// delay=2 cycles = 100ns port_csp0_addr[CCAM_WA_SEQWRD]= sfld_ARST | sfld_xen_imm | sfld_gtNxt | 996 ; // delay=998 cycles = 49.9 us for (i=0;i<18;i++) port_csp0_addr[CCAM_WA_SEQWRD]= sfld_ARST | sfld_xen_imm | sfld_gtNxt | 998 ; // delay=1000 cycles = 50.0 us (x18) port_csp0_addr[CCAM_WA_SEQWRD]= sfld_ARST | sfld_xen_imm |sfld_genIn | 998 ; // delay=1000 cycles = 50.0 us port_csp0_addr[CCAM_WA_WWA]= 0x00; // will get here after trigger port_csp0_addr[CCAM_WA_SEQWRD]= sfld_ARST | sfld_gtNxt ;// one more reset pulse for slow phosphors - OK delay=2 cycles = 100ns if (MCPpresent()) { for (i=0;i<18;i++) port_csp0_addr[CCAM_WA_SEQWRD]= sfld_gtNxt | 998 ; // delay=1000 cycles = 50.0 us (x18) port_csp0_addr[CCAM_WA_SEQWRD]= sfld_xt_rst | sfld_gtNxt | 998 ;// reset "was trigger" flag, delay=1000 cycles = 50.0 us port_csp0_addr[CCAM_WA_SEQWRD]= sfld_genIn | sfld_xen_imm | 998 ; // gen interrupt, delay=1000 cycles = 50.0 us } else { for (i=0;i<18;i++) port_csp0_addr[CCAM_WA_SEQWRD]= sfld_GATE | sfld_gtNxt | 998 ; // delay=1000 cycles = 50.0 us (x18) port_csp0_addr[CCAM_WA_SEQWRD]= sfld_GATE | sfld_xt_rst | sfld_gtNxt | 998 ; // reset "was trigger" flag, delay=1000 cycles = 50.0 us port_csp0_addr[CCAM_WA_SEQWRD]= sfld_GATE | sfld_genIn | sfld_xen_imm | 998 ; // gen interrupt, delay=1000 cycles = 50.0 us }// enable selected interrupts (for now will use internal vector number) - no INTA generated !!!// set all external interrupt vectors to the same as internally generated - 0x2a - WORKS! port_csp0_addr[CCAM_WA_WWA]= 0x00; for (i=0;i<8;i++) port_csp0_addr[CCAM_WA_INTWRWV]= camIRQVectors[i]; // needed even w/o irqs enabled DIS_INTERRUPTS; setCamSeq(0); //stop, init status// if(request_irq( 4, camTrig_interrupt, SA_INTERRUPT, "cmoscam XTRN trigger", NULL)) panic("irq4"); if(request_irq(10, camSeq_interrupt, SA_INTERRUPT, "cmoscam sequencer", NULL)) panic("irq10");// Set external vector number generation// *R_IRQ_MASK0_CLR = 0x10; //1 << irq_int_vector_nr// *R_IRQ_MASK0_SET = 0x20; //1 << irq_ext_vector_nr// No, let's try internal *R_IRQ_MASK0_SET = 0x10; //1 << irq_int_vector_nr printk("CMOS/MCP camera interrupts initialized\n");}static void setCamSeq(int cmd) { // 0 - stop (and turn off video mode?), 1 - run, 2 - set video mode int expTime=imageParamsR[P_EXPOS]; MD(printk ("# 3 state=%x testDMA=%x, expTime= %x, blFrame= %x, cmd=%x\r\n",getCamSeqState(),testDMA,expTime,blFrame,cmd)); MD(printk ("intm_shadow=%x camSeqPreCount=%x, camSeqCount= %x\r\n",intm_shadow,camSeqPreCount,camSeqCount));//intm_shadow if (expTime<0) expTime=0; // - minimum - 1 ms if (expTime>MAXEXPOSURE) expTime=MAXEXPOSURE; if (cmd==2) { // will switch to CAMSEQ_VIDEOON// just in case - stop previous activity DIS_INTERRUPTS; CCAM_EXP_DIS; setCamSeqCount(0); setCamSeqPreCount(2);// stop DMA activity (if any) FPGA_DMA_STOP; RESET_DMA( 5 ); WAIT_DMA( 5 ); setCamSeqState(CAMSEQ_VIDEOON); EN_INTERRUPT(nint_vact_end); MD(printk ("intm_shadow=%x camSeqPreCount=%x, camSeqCount= %x\r\n",intm_shadow,camSeqPreCount,camSeqCount)); return; } else if (cmd==1) { // run if (imageParamsR[P_VIDEO]) {// video mode should be enabled before - while writing parameters switch (camSeqState) { case CAMSEQ_VIDEORDY: //ready to start acquisition case CAMSEQ_VIDEOGOT: {//ready to start acquisition setCamSeqState(CAMSEQ_VIDEOWAIT); RESET_DMA( 5 ); WAIT_DMA( 5 );#ifdef CONFIG_ETRAX_303 ccam_dma_buf0[0]=0x80000000; //to find out if data sent to memory -- 2 MSBs always 0 EN_INTERRUPT(nint_vact_end);#else EN_INTERRUPT(nint_xferovr);#endif *R_DMA_CH5_FIRST = virt_to_phys (&ccam_dma_descr[0]); *R_DMA_CH5_CMD = IO_STATE(R_DMA_CH5_CMD, cmd, start); EXT_DMA_0_START ;// MD(printk ("will set FPGA DMA with %x\r\n",((imageParamsR[P_VIDEO] && imageParamsR[P_TRIG])?RS_EXTERNAL:RS_INTERNAL) | (RS_MAX_LEN & ((imageParamsR[P_IMAGE_SIZE] >>2) + imageParamsR[P_OVERLAP]))));// for REV0 no difference internal/external - always internal if (blFrame) {FPGA_DMA_START_INTERNAL ;} //should be some "nops" after these writes to FPGA else {FPGA_DMA_START ;} } default: return; // do nothing } // switch (camSeqState) return; } else { // still mode setCamSeqCount(expTime); setCamSeqState(CAMSEQ_PREERASE); CCAM_MRST_OFF; // to make sure they are not set CCAM_ARST_OFF; CCAM_ARO_OFF; setCamSeqCount(expTime); setCamSeqPreCount(PREERASE); setCamSeqState(CAMSEQ_PREERASE); port_csp0_addr[CCAM_WA_SEQWRRA]= 0x20; // sequencer start address EN_INTERRUPT(nint_seq_norm); if (blFrame) { CCAM_EXP_DIS;} else {CCAM_EXP_EN;} port_csp0_addr[CCAM_WA_SEQSTART]= 0; } } else if (cmd==0) { // if (imageParamsR[P_VIDEO] && (getCamSeqState()==CAMSEQ_VIDEOON)) return; // find better logic? MD(printk ("disabling interrupts: imageParamsR[P_VIDEO]= %x, getCamSeqState()= %x\r\n",imageParamsR[P_VIDEO],getCamSeqState() )); CCAM_EXP_DIS; DIS_INTERRUPTS; port_csp0_addr[CCAM_WA_SEQSTOP]= 0; port_csp0_addr[CCAM_WA_SEQWRRA]= 0x20; // sequencer start address setCamSeqCount(0); setCamSeqPreCount(0);// stop DMA activity (if any) RESET_DMA( 5 ); WAIT_DMA( 5 ); FPGA_DMA_STOP; if (imageParamsR[P_VIDEO]) { if (getCamSeqState()==CAMSEQ_VIDEOGOT) setCamSeqState(CAMSEQ_VIDEORDY); // reset previous image if (getCamSeqState()==CAMSEQ_VIDEOON) { setCamSeqState(CAMSEQ_OFF); // reset completely imageParamsR[P_VIDEO]=0;// disable video mode toggle ARST; CCAM_ARST_ON ; udelay (1); CCAM_ARST_OFF ; } } else { setCamSeqState(CAMSEQ_OFF);// disable video mode toggle ARST; CCAM_ARST_ON ; udelay (1); CCAM_ARST_OFF ; } }}//writing to CCAM_WA_SEQWRRA should be AFTER EN_INTERRUPT()!! (EN_INTERRUPT after with long MCLK aborts writing CCAM_WA_SEQWRRA)static void camSeq_interrupt(int irq, void *dev_id, struct pt_regs * regs) {// simulate "inta" DIS_INTERRUPTS; // disable and clear all interrupts switch (camSeqState) { case CAMSEQ_PREERASE: case CAMSEQ_WAITTRIG: { //2// check if there was external trigger EN_INTERRUPT(nint_seq_norm); // re-enable sequencer interrupt if (CCAM_SEQ_BEFORE_TRIGER) { // before external trigger port_csp0_addr[CCAM_WA_SEQWRRA]= 0x20; // just loop sequencer waiting cycle if ((camSeqPreCount--) <= 0) camSeqState=CAMSEQ_WAITTRIG; //2 - will decrement camSeqPreCount also in state 2 - OK } else { // after xternal trigger camSeqState=CAMSEQ_TRIGGERED; //3 port_csp0_addr[CCAM_WA_SEQWRRA]= 0x01; // loop sequencer second (post-trigger) waiting cycle } break; } case CAMSEQ_TRIGGERED: { //3 if ((--camSeqCount)<=0) { // exposure over port_csp0_addr[CCAM_WA_SEQSTOP]= 0; // stop sequencer port_csp0_addr[CCAM_WA_WCTL]= (ccam_cr_shadow |= CCAM_BITS(ARO,1) ); // turn ARO on RESET_DMA( 5 ); WAIT_DMA( 5 ); *R_DMA_CH5_FIRST = virt_to_phys (&ccam_dma_descr[0]); *R_DMA_CH5_CMD = IO_STATE(R_DMA_CH5_CMD, cmd, start); EXT_DMA_0_START ; FPGA_DMA_START ; // no FPGA access immediately after this write camSeqCount=0; camSeqState=CAMSEQ_STILLDMA; //4 EN_INTERRUPT(nint_vact_end); // enable end of frame interrupt } else { EN_INTERRUPT(nint_seq_norm); // re-enable sequencer interrupt port_csp0_addr[CCAM_WA_SEQWRRA]= 0x01; // loop sequencer second (post-trigger) waiting cycle } break; } case CAMSEQ_STILLDMA: { // 4 should be end of VACT FPGA_DMA_STOP; camSeqState=CAMSEQ_STILLGOT; // all done ! RESET_DMA( 5 ); WAIT_DMA( 5 ); port_csp0_addr[CCAM_WA_WCTL]= (ccam_cr_shadow &= ~CCAM_BITS(ARO,1) ); // turn ARO off break; }// video modes (for rev 0 will be different - use video wait to delay one more VACT) case CAMSEQ_VIDEOON: { //6 Should be caused by VACT. Advance state and start acquisition in video mode if ((camSeqPreCount--) <= 0) { camSeqState=CAMSEQ_VIDEORDY; } else { EN_INTERRUPT(nint_vact_end); // re-enable end of frame interrupt } break; } case CAMSEQ_VIDEOWAIT: { // 8 Should be caused by nint_xferovr. Advance state and finish#ifdef CONFIG_ETRAX_303 if (ccam_dma_buf0[0] & 0x80000000) {// DMA did not start EN_INTERRUPT(nint_vact_end); // reanable interrupt, wait for the next VACT end break; }#endif FPGA_DMA_STOP; camSeqState=CAMSEQ_VIDEOGOT; // all done ! RESET_DMA( 5 ); WAIT_DMA( 5 ); break; } default: { // unexpected interrupt - just make sure they are off! DIS_INTERRUPTS; // disable and clear all interrupts } }}/* direct port r/w */static int csp0rw_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ D(printk("csp0rw_ioctl cmd= %x, arg= %x\n\r",cmd,arg)); D(printk("csp0rw_ioctl: ((int *)file->private_data)[0]= %x\n\r",((int *)file->private_data)[0])); if(_IOC_TYPE(cmd) != CMOSCAM_IOCTYPE) { return -EINVAL; } if (_IOC_NR(cmd) == IO_CCAM_CR_SHADOW) {// return (long ) ccam_cr_shadow;// could not make ioctl to return 32 bits - all negative become -1// so I'll throw away bit 30 and use it to return bit 31 return (long ) ((ccam_cr_shadow & 0x3fffffff) | ((ccam_cr_shadow >>1) & 0x40000000)); } if (( _IOC_NR(cmd) == IO_CCAM_CR_MODIFY ) |// ( _IOC_NR(cmd) == IO_CCAM_START_DMA ) | ( _IOC_NR(cmd) == IO_CCAM_STOP_DMA ) | ( _IOC_NR(cmd) == IO_CCAM_MONITOR_DMA_DESCR ) | ( _IOC_NR(cmd) == IO_CCAM_MONITOR_DMA_BUFFER ) | ( _IOC_NR(cmd) == IO_CCAM_EXPOSE ) | ( _IOC_NR(cmd) == IO_CCAM_EXPOS_END ) | ( _IOC_NR(cmd) == IO_CCAM_EXPOS_START ) | ( _IOC_NR(cmd) == IO_CCAM_SET_EXT_EXPOSURE ) | ( _IOC_NR(cmd) == IO_CCAM_MONITOR_SEQ ) ) { return ccam_DMA_ioctl (inode,file,cmd,arg); } switch (_IOC_CSP0RW_CMD(cmd)) { case IO_CSP0_R: return (long ) port_csp0_addr[_IOC_CSP0RW_ADR(cmd)]; case IO_CSP0_W: if ((_IOC_CSP0RW_ADR(cmd) & 3) == 1) ccamCRAndOr(0, arg); else port_csp0_addr[_IOC_CSP0RW_ADR(cmd)]=arg; break; default: return -EINVAL; } return 0;}static int ccam_DMA_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg) {// unsigned char i2cdata[2]; unsigned long flags; int i1;// printk("_IOC_NR(cmd)=%lx", _IOC_NR(cmd)); switch(_IOC_NR(cmd)){ case IO_CCAM_MONITOR_SEQ : {// printk("IO_CCAM_MONITOR_SEQ\r\n"); return (arg)? getCamSeqCount(): getCamSeqState(); } case IO_CCAM_SET_EXT_EXPOSURE : {// printk("IO_CCAM_SET_EXT_EXPOSURE\r\n"); blFrame=(arg==2)?1:0; setCamSeq(arg? 1:0); // was arg return 0; } case IO_CCAM_CR_MODIFY : { save_flags(flags); cli(); i1=((ccam_cr_shadow & (1<<(arg>>2)))!=0); switch (arg & 3) { case 1: {ccam_cr_shadow &= ~(1<<(arg>>2));break;} case 2: {ccam_cr_shadow |= (1<<(arg>>2));break;} case 3: {ccam_cr_shadow ^= (1<<(arg>>2));break;} } port_csp0_addr[CCAM_WA_WCTL]= ccam_cr_shadow; restore_flags(flags); return i1; } case IO_CCAM_MONITOR_DMA_DESCR : {// printk("CCAM_MONITOR_DMA_DESCR [%lx] = %lx\r\n", arg, ( (unsigned long *) &ccam_dma_descr[0])[arg]); return (arg < (CCAM_DESCR_SIZE <<2)) ? (( (long *) &ccam_dma_descr[0])[arg] & 0x7fffffff):-EINVAL;// return ( (unsigned long *) &ccam_dma_descr[0])[arg]; } case IO_CCAM_MONITOR_DMA_BUFFER : return (arg < CCAM_DMA_SIZE ) ? (( (long *) &ccam_dma_buf[0])[arg] & 0x7fffffff):-EINVAL; case IO_CCAM_STOP_DMA : { FPGA_DMA_STOP ; EXT_DMA_0_STOP ; RESET_DMA( 5 ); WAIT_DMA( 5 ); } case IO_CCAM_EXPOS_START : CCAM_MRST_OFF ; udelay (1); CCAM_ARO_OFF ; CCAM_ARST_ON ; udelay (1); CCAM_ARST_OFF ; i1=arg;// printk ("i1= %lx\r\n",i1); if (i1>100000) i1=100000; // 1 sec for (;i1>0;i1--) udelay (10); return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -