To demonstrate how to use the Oscilloscope module a light sensor target application will be used. The light sensor example is a rather generic data source where an Analog-to-Digital Converter is used to sample the sensor, and the example applies to a wide range of other data sources.
To be able to view the light sensor data in the Oscilloscope module, the ATmega256RFR2 target has to be programmed with code that samples the light sensor and sends the data to the Embedded Debugger (EDBG) on the ATmega256RFR2 Xplained Pro over a serial interface. The EDBG then uses the Data Gateway Interface (DGI) to send the data to the host computer.
First, a new project for the target application code has to be set up in Atmel Studio.
#include <avr/io.h> #include <avr/interrupt.h> uint16_t adc_value = 0; volatile uint8_t send_data = 0; void adc_init(void){ // Internal 1.5V reference, ADC0 as single ended input ADMUX = (1 << REFS1); // Enable the ADC, auto triggered mode, interrupt on conversion finished ADCSRA |= (1<<ADEN) | (1<<ADATE) | (1<<ADIE); // Timer/Counter compare match A as trigger of ADC conversion ADCSRB |= (1<<ADTS1) | (1<<ADTS0); // Check that the reference is OK while (0x00 == (ADCSRB & (1 << REFOK))); } void spi_init(void){ // Slave select (PB0), MOSI (PB2) and SCK (PB1) as output DDRB |= (1<<PINB0) | (1<<PINB2) | (1<<PINB1); //Slave select high (inactive) PORTB |= (1<<PINB0); // 2X mode, 4MHz SPI clock when CPU clock is 8MHz SPSR |= (1<<SPI2X); // Master mode, enable SPI module. // Clock polarity and phase is kept at default (Sample on rising edge) SPCR = (1<<SPE) | (1<<MSTR); } void spi_send(uint8_t data){ // Slave select low PORTB &= ~(1<<PINB0); // Write data to shift register SPDR = data; // Wait for the transmission to complete while (0x00 == (SPSR & (1<<SPIF))); // Slave select high PORTB |= (1<<PINB0); } void timer_init(){ // Set TOP value for timer (output compare A value) OCR0A = 80; // Clear timer on compare match mode TCCR0A = (1<<WGM01); // Timer clocked by CPU clock, no prescaler TCCR0B = (1<<CS00); } ISR (ADC_vect){ // Store the light sensor sample adc_value = (ADC); // Clear timer interrupt flag to enable the next sample TIFR0 |= (1<<OCF0A); // Flag sending of data to host send_data = 1; } int main(void){ timer_init(); adc_init(); spi_init(); // Interrupts on sei(); while (1){ if (1 == send_data){ send_data = 0; // Send the ADC value over SPI to the host // Only the 8 lower bits contain useful data spi_send(adc_value & 0xFF); } } }
The code configures the ADC to take a new sample every 10th μs giving a sample rate of 100 kHz. This is achieved by using a timer that counts up to 80 before resetting. The code is based on the target CPU running on the internal 16 MHz clock with a clock prescaler of 2 (default) and the CKDIV8 fuse not set. The data samples are sent to the EDBG over the DGI SPI interface. The SPI interface is running at 4 MHz. The ATmega256RFR2 ADC is 10-bit but only the lower 8 bits contain useful data in this example.