// The U-series device has a 12-bit 1MSample/second Successive Approximation Register (SAR) Analogue to Digital // Converter (ADC). It has 4 input pins which are multiplexed into the ADC. The sampling of the ADC is controlled using // GPIO pin X0D24 that is triggered either by writing to port 1I, or by driving the pin externally. On each rising edge // of the sample pin the ADC samples, holds and converts the data value from one of the analog input pins. Each of the // 4 inputs can be enabled individually. Each of the enabled analog inputs is sampled in turn, on successive rising // edges of the sample pin. The data is transmitted to the channel-end that the user configures during initialization // of the ADC. Data is transmitted over the channel in individual packets, or in packets that contain multiple // consecutive samples. The ADC uses an external reference voltage, nominally 3V3, which represents the full range of // the ADC. #include "xsystem_xs1u_adc.h" //#include "xconfig.h" #ifdef XSYSTEM_XS1U_ADC #include #include #include #include #include #ifndef XSYSTEM_XS1U_ADC__TRIGGER_MODE #error "XSYSTEM_XS1U_ADC__TRIGGER_MODE not defined" #endif static unsigned int xsystem_xs1u_adc__configuration[5][1] = {{0},{0},{0},{0},{0}}; static unsigned int xsystem_xs1u_adc__sample_format = 0; static unsigned int xsystem_xs1u_adc__channel_mask = 0; static unsigned int xsystem_xs1u_adc__enabled_flag = 0; #if XSYSTEM_XS1U_ADC__TRIGGER_MODE == XSYSTEM_XS1U_ADC__TRIGGER_MODE__INTERNAL on tile[0] : out port xsystem_xs1u_adc__trigger_port = XS1_PORT_1I; #endif static inline unsigned _chanend_res_id( chanend c ) { unsigned int id; asm("mov %0, %1" : "=r"(id): "r"(c)); return id; } #if XSYSTEM_XS1U_ADC__TRIGGER_MODE == XSYSTEM_XS1U_ADC__TRIGGER_MODE__INTERNAL void _xsystem_xs1u_adc__trigger( void ) { unsigned time; xsystem_xs1u_adc__trigger_port <: 1 @ time; time += 40; // Ensure 1 is held for >400ns xsystem_xs1u_adc__trigger_port @ time <: 0x80000; time += 40; // Ensure 0 is held for >400ns xsystem_xs1u_adc__trigger_port @ time <: 0x00000; } #endif void xsystem_xs1u_adc__initialize( chanend data_channel, int sample_width, int channel_mask ) { int count = 0; xsystem_xs1u_adc__channel_mask = channel_mask; switch( sample_width ) { case 1: xsystem_xs1u_adc__sample_format = 0; break; case 2: xsystem_xs1u_adc__sample_format = 1; break; case 4: xsystem_xs1u_adc__sample_format = 3; break; default: /*ASSERT*/ break; } // Drive trigger port low to ensure calibration pulses are all seen // Perform the ADC calibration - requires a number of initial pulses (6 for the U-series) #if XSYSTEM_XS1U_ADC__TRIGGER_MODE == XSYSTEM_XS1U_ADC__TRIGGER_MODE__INTERNAL xsystem_xs1u_adc__trigger_port <: 0; #endif // Configure ADC Inputs // Write each ADC input channel control register for( int ii = 0; ii < 4; ++ii ) { xsystem_xs1u_adc__configuration[ii][0] = 0; if( channel_mask & (1<< ii) ) { xsystem_xs1u_adc__configuration[ii][0] = 1 | (_chanend_res_id(data_channel) & ~0xff); ++count; } } // Configure ADC - Write the ADC general control register xsystem_xs1u_adc__configuration[4][0] = 0; if( channel_mask != 0 ) xsystem_xs1u_adc__configuration[4][0] |= 0x01; //if( use_internal_ref != 0 ) xsystem_xs1u_adc__configuration[4] |= 0x02; xsystem_xs1u_adc__configuration[4][0] |= (xsystem_xs1u_adc__sample_format & 3) << 16; xsystem_xs1u_adc__configuration[4][0] |= (count & 255) << 8; printhexln( xsystem_xs1u_adc__configuration[4][0] ); } void xsystem_xs1u_adc__enable( void ) { unsigned int data[1] = {0}; // Ensure that the global configuration is disabled, otherwise the individual ADC config regs are read-only write_periph_32( usb_tile, 2, 0x20, 1, data ); // Drive trigger port low to ensure calibration pulses are all seen // Perform the ADC calibration - requires a number of initial pulses (6 for the U-series) #if XSYSTEM_XS1U_ADC__TRIGGER_MODE == XSYSTEM_XS1U_ADC__TRIGGER_MODE__INTERNAL xsystem_xs1u_adc__trigger_port <: 0; #endif // Configure each ADC input write_periph_32( usb_tile, 2, 0x00, 1, xsystem_xs1u_adc__configuration[0] ); write_periph_32( usb_tile, 2, 0x04, 1, xsystem_xs1u_adc__configuration[1] ); write_periph_32( usb_tile, 2, 0x08, 1, xsystem_xs1u_adc__configuration[2] ); write_periph_32( usb_tile, 2, 0x0C, 1, xsystem_xs1u_adc__configuration[3] ); // Configure ADC - Write the ADC general control register write_periph_32( usb_tile, 2, 0x20, 1, xsystem_xs1u_adc__configuration[4] ); // Perform the ADC calibration - requires a number of initial pulses (6 for the U-series) #if XSYSTEM_XS1U_ADC__TRIGGER_MODE == XSYSTEM_XS1U_ADC__TRIGGER_MODE__INTERNAL for( int i = 0; i < 6; i++ ) _xsystem_xs1u_adc__trigger(); #endif xsystem_xs1u_adc__enabled_flag = 1; } void xsystem_xs1u_adc__disable( void ) { unsigned data[1] = {0}; write_periph_32(usb_tile, 2, 0x20, 1, data); xsystem_xs1u_adc__enabled_flag = 0; } void xsystem_xs1u_adc__read( chanend data_channel, unsigned int sample_data[4] ) { if( !xsystem_xs1u_adc__enabled_flag ) { sample_data[0] = sample_data[1] = sample_data[2] = sample_data[3] = 0; return; } for( int ii = 0; ii < 4; ii++ ) { if( xsystem_xs1u_adc__channel_mask & (1<>= 4; break; case 3: sample_data[ii] = inuint( data_channel ); sample_data[ii] >>= 20; break; } } else sample_data[ii] = 0; } chkct( data_channel, XS1_CT_END ); } #endif