//----------------------------------------------------------------------------- // Main Routine //----------------------------------------------------------------------------- void main(void) { USB_Clock_Start(); // Init USB clock *before* calling USB_Init USB_Init(USB_VID,USB_PID,USB_MfrStr,USB_ProductStr,USB_SerialStr,USB_MaxPower,USB_PwAttributes,USB_bcdDevice); CLKSEL |= 0x02; RSTSRC |= 0x02; Port_Init(); // Initialize crossbar and GPIO USB_Int_Enable(); // Enable USB_API Interrupts while (1); }
//----------------------------------------------------------------------------- // Main Routine // after initialization, the program simply polls the !req input and when // !req goes low, !ack on is lowered to acknowledge, // the address is captured in P1 (AE0-7) and P2 (AE8-15) and is copied to XRAM. // Then !ack is raised, we wait for !req to go high and start over. // We initiate BlockWrite in main after disabling interrupts. This is not advised because // device is not supposed to intiate transfers, but it works fine, at least in USBXPress v2.1 // Commands are handled in the USB ISR. //----------------------------------------------------------------------------- void main(void) { PCA0MD &= ~0x40; // Disable Watchdog timer /** SPI info 18.1.4. Slave Select (NSS) The function of the slave-select (NSS) signal is dependent on the setting of the NSSMD1 and NSSMD0 bits in the SPI0CN register. There are three possible modes that can be selected with these bits: 1.NSSMD[1:0] = 00: 3-Wire Master or 3-Wire Slave Mode: SPI0 operates in 3-wire mode, and NSS is disabled. When operating as a slave device, SPI0 is always selected in 3-wire mode. Since no select signal is present, SPI0 must be the only slave on the bus in 3-wire mode. This is intended for point-to-point communication between a master and one slave. http://www.cygnal.org/ubb/Forum1/HTML/000157.html "The SPI0 is set in 3-wire single master mode." To configure the SPI to 3-wire mode, set it to 3-wire mode before attaching it to the crossbar. If this order is reversed, NSS signal is assigned overlapping on other peripheral pins. SPI0CN = 0x00; // 3-wire master mode XBR0 = 0x02; // attach SPI to crossbar */ config(); /* 3.1. USB_Init Description: Enables the USB interface and the use of Device Interface Functions. On return, the USB interface is configured, including the USB clock and memory. Neither the system or USB clock configurations should be modified by user software after calling the USB_Init function. See Appendix A for a complete list of SFRs that should not be modified after USB_Init is called. In addition, C8051F32x interrupts are globally enabled on the return of this function. User software should not globally disable interrupts (set EA = 0) but should enable/disable user configured interrupts individually using the interrupt's source interrupt enable flag. This function allows the user to specify the Vendor and Product IDs as well as a Manufacturer, Product Description and Serial Number string returned as part of the device's USB descriptor during the USB enumeration (connection). note that ProductID is important that windows hardware installation wizard can find the USBXPress driver this driver must be preinstalled before plugging in device see the Preinstaller but note that path in .ini file may need to be changed for preinstaller to locate driver files so that they can be copied to standard windows driver search folder for drivers. this initVariables is for 60mA device, bus powered, serial number 1.00 */ //void USB_Init (int VendorID, int ProductID, uchar *ManufacturerStr,uchar *ProductStr, uchar *SerialNumberStr, byte MaxPower, byte PwAttributes, uint bcdDevice) USB_Init (0, 0xEA61, ManufacturerStr, ProductStr, SerialNumberStr,30,0x80,0x0100); // very important, USB_Init should be called AFTER config() so that USB clock is setup correctly. //Config doesn't deal with USB at all. CLKSEL |= 0x02; // system clock 24MHz (48MHz USB/2) RSTSRC |= 0x02; // power on reset IP=0x01; // ext int 0 high priority ?? LedOrangeOn(); //SPIEN=1; // enable SPI interface -- leave it enabled so that output port SCK and MOSI don't float initVariables(); isActive=0; USB_Int_Enable(); // Enable USB_API Interrupts // send the bias values from flash memory out the SPI port sendFlashedBiases(); while (1){ if(isActive){ while(NOTREQ==1) { // wait for !req low if( TH1==0xFF){ // while polling req, check if we have wrapped timer1 since last transfer if(AECounter>0){ sendEvents(); // if so just send available events } } } LedOrangeOn(); // got req NOTACK=0; // lower acknowledge //USB_Int_Disable(); // using these functions increases cycle time to >8us EA=0; // disable interrupts during snapshot of AE to avoid USB interrupt during snapshot //note according to C51 compiler specs, shorts are stored big-endian, MSB comes first *AEPtr++=P2; // AE8-15 *AEPtr++=P1; // AE07 *AEPtr++=PCA0CPH0; // captured PCA counter/timer MSB. This was captured by req low. *AEPtr++=PCA0CPL0; // timer LSB. AECounter++; // increment counter for events EA=1; // reenable interrupts // USB_Int_Enable(); // using these functions increases cycle time to >8us // very important!!!! // check HERE if buffer is full so that last request is acknowledged and retina can take away its // request before the pause to transmit events over USB. during this transfer, the usb chip // has acknowledged and the retina takes away its request, but it cannot generate a new request // until the USB chip takes away its ack, below. // if this is not done in this order, you get vertical streaks of events, because (hyppothesis) // the retina is not rapidly acknowledged and therefore it is still pulling down on the column req // line and pulling it to ground. this makes it easier for other pixels in the same column to generate // new events, compared with normally-timed handshake cyles. with the present timing scheme, the retina // is acknowledged with normal timing, and therefore the pixel takes away its request with normal timing. // this is the working hypothesis. if(AECounter==AE_BUFFER_SIZE){ // when we have collected buffer, initiate transfer // during this 860us no handshaking is occurring sendEvents(); } // if the retina is powered off, then its req will be low (no power). so this code will come here and // will have lowered ack and stored a bogus address. now it will wait for req to go high. // but req will be low from the retina and won't go high // because ack is low. therefore we can get stuck here if the retina is powered on after reset. while(NOTREQ==0){ // wait for req to go high if( TH1==0xFF) { // while polling req, check if we have wrapped timer1 since last transfer TH1=0; AECounter--; // throw away that event break; // break from possibly infinite loop. this will raise ack } } NOTACK=1; // raise acknowledge, completing handshake LedOrangeOff(); // got req // }else if(state==ST_WAITING){ }else{ // isActive is false, USB not open, just handshake // plain handshake cycle is about 1+/-0.2us while(NOTREQ==1) { // wait for !req low if( TH1==0xFF) { // while polling req, check if we have wrapped timer1 since last transfer TH1=0; NOTACK=0; NOTACK=1; // toggle ack an extra time in case we are stuck } } LedOrangeOn(); // !req received NOTACK=0; // lower acknowledge while(NOTREQ==0){ // wait for req to go high if( TH1==0xFF) { // while polling req, check if we have wrapped timer1 since last transfer TH1=0; break; // break from possibly infinite loop } } NOTACK=1; // raise acknowledge, completing handshake LedOrangeOff(); } } }
//----------------------------------------------------------------------------- // Main Routine // after initialization, the program simply polls the !req input and when // !req goes low, !ack on P0.1 is lowered to acknowledge, // the address is captured in P1 (AE0-7) and P2 (AE8-15) and is copied to XRAM. // Then !ack is raised, we wait for !req to go high and start over. // When we get an interrupt from USB, we transmit the existing buffer of data. //----------------------------------------------------------------------------- void main(void) { PCA0MD &= ~0x40; // Disable Watchdog timer //void USB_Init (int VendorID, int ProductID, uchar *ManufacturerStr,uchar *ProductStr, uchar *SerialNumberStr, byte MaxPower, byte PwAttributes, uint bcdDevice) // note that ProductID is important that windows hardware installation wizard can find the USBXPress driver // this driver must be preinstalled before plugging in device // see the Preinstaller but note that path in .ini file may need to be changed for preinstaller to locate driver files // so that they can be copied to standard windows driver search folder for drivers. // this initVariables is for 60mA device, bus powered, serial number 1.00 USB_Init (0, 0xEA61, ManufacturerStr, ProductStr, SerialNumberStr,250,0x80,0x0100); CLKSEL |= 0x02; // system clock 24MHz (48MHz USB/2) RSTSRC |= 0x02; // power on reset Timer_Init(); // Init Timer and Capture for event timing. Init PCA peripheral before port init. Port_Init(); // Initialize crossbar and GPIO initVariables(); LedGreenOff(); LedBlueOff(); /* LedRedOn(); delay(); LedRedOff(); LedGreenOn(); delay(); LedGreenOff(); LedBlueOn(); delay(); LedBlueOff(); */ //flushEvents(); // flush some events in case the sender has been powered up //state=ST_WAITING; isActive=0; USB_Int_Enable(); // Enable USB_API Interrupts while (1){ // if(state==ST_ACTIVE){ if(isActive){ while(NOTREQ==1) { // wait for !req low if( TH1==0xFF){ // while polling req, check if we have wrapped timer1 since last transfer if(AECounter>0){ sendEvents(); // if so just send available events } } } LedGreenOn(); // got req NOTACK=0; // lower acknowledge //USB_Int_Disable(); // using these functions increases cycle time to >8us EA=0; // disable interrupts during snapshot of AE to avoid USB interrupt during snapshot //note according to C51 compiler specs, shorts are stored big-endian, MSB comes first *AEPtr++=P2; // AE8-15 *AEPtr++=P1; // AE07 *AEPtr++=PCA0CPH0; // captured PCA counter/timer MSB. This was captured by req low. *AEPtr++=PCA0CPL0; // timer LSB. AECounter++; // increment counter for events EA=1; // reenable interrupts // USB_Int_Enable(); // using these functions increases cycle time to >8us // if the retina is powered off, then its req will be low (no power). so this code will come here and // will have lowered ack and stored a bogus address. now it will wait for req to go high. // but req will be low from the retina and won't go high // because ack is low. therefore we can get stuck here if the retina is powered on after reset. while(NOTREQ==0){ // wait for req to go high if( TH1==0xFF) { // while polling req, check if we have wrapped timer1 since last transfer TH1=0; AECounter--; // throw away that event break; // break from possibly infinite loop. this will raise ack } } NOTACK=1; // raise acknowledge, completing handshake LedGreenOff(); // got req if(AECounter==AE_BUFFER_SIZE){ // when we have collected buffer, initiate transfer // during this 860us no handshaking is occurring sendEvents(); } // }else if(state==ST_WAITING){ }else{ // isActive is false, USB not open, just handshake // plain handshake cycle is about 1+/-0.2us while(NOTREQ==1) { // wait for !req low if( TH1==0xFF) { // while polling req, check if we have wrapped timer1 since last transfer TH1=0; NOTACK=0; NOTACK=1; // toggle ack an extra time in case we are stuck } } LedGreenOn(); // !req received NOTACK=0; // lower acknowledge while(NOTREQ==0){ // wait for req to go high if( TH1==0xFF) { // while polling req, check if we have wrapped timer1 since last transfer TH1=0; break; // break from possibly infinite loop } } NOTACK=1; // raise acknowledge, completing handshake LedGreenOff(); } } }