⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.c

📁 10MS/s USB-2.0 ("high speed") oscilloscope with two 8 bit sampling inputs
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * main.c -- USBLiveOsci clock generator.  *  * Copyright (c) 2006 by Wolfgang WIESER <wwieser@gmx.de> *  */#include <inttypes.h>#include <avr/signal.h>#include <avr/io.h>#include <avr/wdt.h>#include <avr/interrupt.h>#include "../defines.h"#define nop()  __asm__ __volatile__("nop")typedef signed char int8;typedef uint8_t uint8;typedef uint16_t uint16;typedef uint32_t uint32;// This should be in attiny2313 headers: #define TCCR0A	_SFR_IO8(0x30)#define TCCR0B	_SFR_IO8(0x33)#define OCR0A	_SFR_IO8(0x36)#define TIMSK	_SFR_IO8(0x39)#define TCNT0	_SFR_IO8(0x32)#define SIG_INTERRUPT0 _VECTOR(1)#define SIG_INTERRUPT1 _VECTOR(2)#define SIG_OVERFLOW0 _VECTOR(6)#define SIG_OUTPUT_COMPARE0A _VECTOR(0xd)#define SCK_LEVEL()  (PIND & (1U<<4))  /* NOTE: Result is 0 or !=0. */#define RXD_LEVEL()  (PIND & (1U<<0))  /* NOTE: Result is 0 or !=0. */#define SET_TXD_HIGH()  sbi(PORTD,1)#define SET_TXD_LOW()   cbi(PORTD,1)// PD3 is INT1. Result is 0 or !=0. HIGH=sampling, LOW=IO. #define INT1_LEVEL()  (PIND & (1U<<3))// Note: To disrespect INT1 while still producing the correct timings, //       we should use another pin like (PIND & (1U<<5)) [unused] and //       set it up properly. //#define INT1_LEVEL()   (1) /* Ignore pin; always sample. *///==============================================================================// ALL GLOBAL VARS GO HERE, BEFORE THE FIRST FUNCTION DEF. //==============================================================================// Clock speed value in multiples of 50kS/s. // Only certain discrete values are allowed; see ClockGeneratorLoop(). volatile uint8 clock_speed=200;  // 200 -> 10MS/s; 50 -> 2.5MS/s// For external interrupt 0: SIGNAL(SIG_INTERRUPT0){	// Not needed. Should never trigger. }// For external interrupt 1: SIGNAL(SIG_INTERRUPT1){	// Not needed. Should never trigger. }SIGNAL(SIG_OVERFLOW0){	/*cbi(PORTB,3);	sbi(PORTB,3);*/}SIGNAL(SIG_OUTPUT_COMPARE0A){	/*cbi(PORTB,3);	sbi(PORTB,3);*/}static void Initialize(){	// Disable watchdog timer (be sure). 	wdt_disable();		// Disable analog comparator (to be sure). 	sbi(ACSR,7);		// ----- IO SETUP -----		// PB2,3 are outputs. 	sbi(PORTB,2);  sbi(DDRB,2);   // PB2: clock1, high -> "don't sample"	cbi(PORTB,3);  sbi(DDRB,3);   // PB3: clock0, low		// PD0,2,3,4 is input with pullup. 	cbi(DDRD,0);  sbi(PORTD,0);	cbi(DDRD,2);  sbi(PORTD,2); 	cbi(DDRD,3);  sbi(PORTD,3); 	cbi(DDRD,4);  sbi(PORTD,4);		// PD1, PD6 are outputs. 	cbi(PORTD,1);  sbi(DDRD,1);   // PD1: TxD, low	sbi(PORTD,6);  sbi(DDRD,6);   // PD6: aux, high		// Set up INT1 (PD3) as edge triggered: H -> L (negative edge): 0000 1000	//MCUCR=0x08U;	// Enable INT1: 	//sbi(GIMSK,7);}// We need to sync on the main clock. // The previous method assigning TCNT1 will not work because this can // insert a tiny clock gap for the main clock messing up the FX2 (IMO). // At least it took me some hours to figure out that the assignment to // TCNT1 was the reason for the USB traffic to stall mysteriously although // the relative timing of the write strobes was correct. // Polling TCNT1 instead of the assignment did not work properly for me. // So, the new method uses a loop and polls the output pin directly. // The polling loop must have an odd number of instructions to ensure that // we see different states of the pin each time. (I verified that even // numbers WILL cause hangs!) // Okay, this is not the smartest method but it is implemented quickly and // since we will never have more than 2 iterations in the loop, execution // speed does not matter as well. // NOTE: SampleClockSync_ASM will clobber r24. #define SampleClockSync_ASM  \	   "in   r24, 0x16"    "\n"     /* (1) Read PINB into r24.       */  \	"	andi r24, 0x08"    "\n"     /* (1) Check if bit 3 is set.    */  \	"	nop"               "\n"     /* (1) To make clock count odd.  */  \	"	breq .-8"          "\n"     /* (1/2) 2 clocks in loop -> 4   */// Tiny delay loop. Will make "count"-many iterations. // Each iteration makes 4 cycles; setup is compensated by last iteration. // Hence, total number of cycles is 4*count. // NOTE: Since this is ASM, insert count as string literal. // NOTE: Will clobber r24. #define DelayLoop_ASM(count) \	"	ldi r24, " count "-1" "\n"/* (1) */ \	"	nop"             "\n"     /* (1) */ \	"	subi r24, 0x01"  "\n"     /* (1) */ \	"	brcc .-6"        "\n"     /* (2), (1 for last, compensated by first) */// Three clock cycles (while looping) end-of-loop conditional jump statement. // Must pass label name as string.  #define SampleClockLoopEnd_ASM(label) \	"	sbic 0x10, 3"    "\n"     /* (1) */ \	"	rjmp " label     "\n"     /* (2) */// Must pass label and delay as strings. // Total cycle time is 4*delay + 8. #define SampleClockLoopWithDelay(label,delay) \	__asm__ __volatile__( \		SampleClockSync_ASM       /* Sync on clock; will clobber r24 */ \		label ":"           "\n"  /* Loop start label.               */ \		"	cbi 0x18, 2"    "\n"  /* (2)  cbi(PORTB,2);              */ \		"	sbi 0x18, 2"    "\n"  /* (2)  sbi(PORTB,2);              */ \		"	nop"            "\n"  /* (1)  nop();                     */ \		DelayLoop_ASM(delay)      /* (4*delay) delay; clobbers r24   */ \		SampleClockLoopEnd_ASM(label) /* (3)                         */ \		: /* output operands */   /* SUM: 4*delay+8 cycles           */ \		: /* input operands */                                          \		: "r24" /* clobbered registers */ )// This will set up the main sample timer at 10MHz. // The 50% duty cycle waveform is available on pin PB3 (clock0). // There is no reason to ever stop the sampling clock; we just run the // AD converter at this speed and don't need to actually store the samples. static void StartSampleClock(){	// clock0 (PB3): Set up timer0 in CTC mode: 	// Prescaler to 1: 	// wgm1 3:0 = 0100	OCR1A=0x0;  // 0x00	TCNT1=0;	TCCR1A=0x40U;   // 01000000 <-- COM1A1:0, WGM11:0	TCCR1B=0x09U;   // 00001001  <-- WGM13:2, CS12:0	TCNT1=0;}// NOTE: PIND:3 is HIGH while sampling and LOW during communication. // NOTE: The write strobe must be LOW during a RISING edge of the sampling //       clock. No inverters are in the signal lines. static void ClockGeneratorLoop(){	// Main loop. This runs until PD3 is pulled LOW thereby stopping sampling. 	if(!INT1_LEVEL()) return;		switch(clock_speed)	{		case   0:  // 0kS			// This will store NO samples at all. 			sbi(PORTB,2);  // Already HIGH. 			// Wait for INT1 to go LOW. 			while(INT1_LEVEL());			break;		case   1:  // 50kS			// This will store every 200th sample: (50 kS)			// Cycle sum: 4*98+8 = 400 (OK). 			SampleClockLoopWithDelay("sl50","0x62");			break;		case   2:  // 100kS			// This will store every 100th sample: (100 kS)			// Cycle sum: 4*48+8 = 200 (OK). 			SampleClockLoopWithDelay("sl100","0x30");			break;		case   5:  // 250kS			// This will store every 40th sample: (250 kS)			// Cycle sum: 4*18+8 = 80 (OK). 			SampleClockLoopWithDelay("sl250","0x12");			break;		case  10:  // 500kS			// This will store every 20th sample: (500 kS)			// Cycle sum: 4*8+8 = 40 (OK). 			SampleClockLoopWithDelay("sl500","0x08");			break;		case  20:  // 1MS			// This will store every 10th sample: (1 MS)			// Cycle sum: 4*3+8 = 20 (OK). 			SampleClockLoopWithDelay("sl1000","0x03");			break;		case  50:  // 2.5MS			// This will store every 4th sample: (2.5 MS)			__asm__ __volatile__( \				SampleClockSync_ASM       /* Sync on clock; will clobber r24 */ \				"sl2500:"           "\n"  /* Loop start label.               */ \				"	cbi 0x18, 2"    "\n"  /* (2)  cbi(PORTB,2);              */ \				"	sbi 0x18, 2"    "\n"  /* (2)  sbi(PORTB,2);              */ \				"	nop"            "\n"  /* (1)  nop();                     */ \				SampleClockLoopEnd_ASM("sl2500") /* (3)                      */ \				: /* output operands */   /* SUM: 8 cycles (OK)              */ \				: /* input operands */                                          \				: "r24" /* clobbered registers */ );			break;		case 100:  // 5MS			// This will store every 2nd sample: (5 MS)			// clock1 (PB2): Set up timer0 in CTC mode. Prescaler to 1: 			// TCCR0A: COM0A1 COM0A0 COM0B1 COM0B0    0     0  WGM01 WGM00			//           0       1     0      0       0     0     1    0			// TCCR0B: FOC0A  FOC0B    0      0     WGM02 CS02 CS01  CS00			//           0       0     0      0       0     0    0     1			// Set: COM0A1=0, COMA0=1 -> toggle on compare match			//      WGM02=0, WGM01=1, WGM00=0 -> CTC mode			//      CS02=0, CS01=0, CS00=1 -> system clock						OCR0A=0x01;  // "TOP" value. 						// FUCK IT!! I was the hell not able to find out how to gracefully 			//           start this fucking wave without at least one undesired 			//           spike at the beginning. I should be possible, though. 			// So, my solution is to temporarily switch off the port. GRRR!!!			//sbi(PORTB,2); // (already)			cbi(DDRB,2);    // <-- Switch off port (pull-up still active). 			TCNT0=0x01;  // Counter register. 			TCCR0A=0x42U|0x80U;      // 11000010  (set on compare match)			TCCR0B=0xf0U;      // Force a compare. 			sbi(DDRB,2);    // <-- Switch on port. 						TCNT0=0xff;     // Counter register. 			TCCR0A=0x42U;   // 01000010   <-- COM0A1:0, WGM00:1			// NOTE: The clock source is still switched off; this is done 			//       by setting the lowest bit in TCCR0B, but synchronized!			//TCCR0B=0x01U;      // 00000001			__asm__ __volatile__( \				SampleClockSync_ASM       /* Sync on clock; will clobber r24 */ \				"nop"              "\n"   /* (1)                             */ \				"ldi r24, 0x01"    "\n"   /* (1)                             */ \				"out 0x33, r24"    "\n"   /* (1) TCCR0B                      */ \				: /* output operands */                                         \				: /* input operands */                                          \				: "r24" /* clobbered registers */ );			while(INT1_LEVEL());			break;		case 200:  // 10MS			// This will store all samples: (10 MS)			__asm__ __volatile__( \				SampleClockSync_ASM       /* Sync on clock; will clobber r24 */ \				"cbi 0x18, 2"      "\n"   /* (2) cbi(PORTB,2);               */ \				: /* output operands */                                         \				: /* input operands */                                          \				: "r24" /* clobbered registers */ );			// Sample until INT1 goes LOW. 			while(INT1_LEVEL());			break;		default:			// This is an error. 			// Don't sample: 			sbi(PORTB,2);  // Already HIGH but be sure. 			// Wait for INT1 to go LOW. 			while(INT1_LEVEL());			break;	}		// Stop recording: This works for sampling modes based on internal counter. 	TCCR0B=0x0U;	TCCR0A=0x4U;	OCR0A=0x0;	// No recording: This works for all sampling modes not using the 	// internal counter. 	sbi(PORTB,2);}// Returns the read byte in the lower 8 bit and status in the higher 8 bit. // Status is 0 for success and 1 if stopped by PD3=HIGH. // Will write back the passed value during transfer. static uint16 SerialIOByte(uint8 to_send)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -