In " Optical Spectrometer using a Linear CCD image sensor "
You will find a tutorial to get started with the TC1340 sensor. They are using a slower ARM Cortex M3 than the Sam3x (DUE), hence there is no real issue to read this sensor with a DUE.
Page 3 of this tutorial:
The OS (output) signal has a frequency of ϕM/4 = 250KHz, meaning that for every 4 periods of master clock (1 MHz), the value of a new pixel is shifted to the output signal, until either a new ICG pulse commences or all 3694 pixels have been in rotation, including the dummy ones. Note that Master frequency could be either 0.8 MHz.
You should first focus on the first part of the project, reading TC1340 properly once. The output of results should be addressed later.
You need to program and synchronize several timers, at least 4, you need to start ADC samplings, OS, when ICG rises up with a frequency of 250 KHz, and finally you need to log ADC samplings (it's a good idea to use a PDC DMA to free the uc core for the printing process in step 2).
From the above thoughs, it's obvious that you can't use the Free Running mode for ADC samplings. Here is an example sketch to sample at 250 KHz and log results with a PDC DMA:
/**************************************************************************/
/* ADC sampling frequency = 250 KHz */
/**************************************************************************/
volatile int bufn, obufn;
const uint16_t bufsize = 256;
uint16_t buf[4][bufsize];
void setup()
{
pinMode(LED_BUILTIN, OUTPUT);
adc_setup();
tc_setup();
}
void loop()
{
}
/************* Configure ADC function *******************/
void adc_setup() {
PMC->PMC_PCER1 |= PMC_PCER1_PID37; // ADC power on
ADC->ADC_CR = ADC_CR_SWRST; // Reset ADC
ADC->ADC_MR |= ADC_MR_TRGEN_EN // Hardware trigger select
| ADC_MR_TRGSEL_ADC_TRIG3; // Trigger by TIOA2
ADC->ADC_CHER = ADC_CHER_CH7; // Enable ADC CH7 = A0
ADC->ADC_IER |= ADC_IER_ENDRX ;
NVIC_EnableIRQ(ADC_IRQn); // Enable ADC interrupt
/************* PDC/DMA buffer filling *******************/
ADC->ADC_RPR = (uint32_t)buf[0]; // DMA buffer
ADC->ADC_RCR = bufsize;
ADC->ADC_RNPR = (uint32_t)buf[1]; // next DMA buffer
ADC->ADC_RNCR = bufsize;
bufn = obufn = 1;
ADC->ADC_PTCR |= ADC_PTCR_RXTEN; // Enable PDC receiver channel request
ADC->ADC_CR = ADC_CR_START;
}
void ADC_Handler() { // move DMA pointer to next buffer
// if ( ADC->ADC_ISR & ADC_ISR_ENDRX) { // Useless since this is the only one triggered
bufn = (bufn + 1) & 3;
ADC->ADC_RNPR = (uint32_t)buf[bufn];
ADC->ADC_RNCR = bufsize;
// }
// For debugging only
static uint32_t Count;
if (Count++ == 976) { // 250000/256 ~976
Count = 0;
PIOB->PIO_ODSR ^= PIO_ODSR_P27; // Toggle LED_BUILTIN every 1 Hz
}
}
/************* Timer Counter 0 Channel 2 to generate PWM pulses thru TIOA2 ************/
void tc_setup() {
PMC->PMC_PCER0 |= PMC_PCER0_PID29; // TC2 power ON : Timer Counter 0 channel 2 IS TC2
TC0->TC_CHANNEL[2].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK1 // MCK/2, clk on rising edge
| TC_CMR_WAVE // Waveform mode
| TC_CMR_WAVSEL_UP_RC // UP mode with automatic trigger on RC Compare
| TC_CMR_ACPA_CLEAR // Clear TIOA2 on RA compare match
| TC_CMR_ACPC_SET; // Set TIOA2 on RC compare match
TC0->TC_CHANNEL[2].TC_RC = 168; //<********************* Frequency = (Mck/2)/TC_RC Hz
TC0->TC_CHANNEL[2].TC_RA = 40; //<******************** Any Duty cycle in between 1 and TC_RC
TC0->TC_CHANNEL[2].TC_IER = TC_IER_CPCS;
NVIC_EnableIRQ(TC2_IRQn);
TC0->TC_CHANNEL[2].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN; // Software trigger TC2 counter and enable
}
void TC2_Handler() {
static uint32_t Count;
TC0->TC_CHANNEL[2].TC_SR;
/*
if (Count++ == 250000) {
PIOB->PIO_ODSR ^= PIO_ODSR_P27;
Count = 0;
}
*/
}
Program each of the 4 timers you need as per Figure 2, page 3, and log ADC samplings until everything is correct.