Hello World,
This is my first post on the forum. I am a largely self taught arduino hobbyist and much of my knowledge regarding this device has come from extensively going through the Due forums and from the atmel manual of course. With that said, let me present my problems below and the ask for the clarifications that I seek.
I am trying to read the data from a linear image sensor chip rigged from a bar code scanner, which has 3694 elements/pixels in it. The data from this chip is read out every 15 milliseconds. I am able to successfully read the data on a borrowed oscilloscope. I am now looking to eliminate the oscilloscope completely from the setup and read the data from the Due itself, since this can obviously do the job. For this, I need to initialize an ADC channel, save the data in a DMA buffer, and transmit it to the PC from the Arduino due (relatively straightforward). My code for the same looks something like this –
volatile int bufn,obufn;
const uint16_t bufsize=4096;
uint16_t buf[4][bufsize]; // Size of buffer must be a power of 2
void startA2DConvTimer(uint32_t ADCPulseWidth,uint32_t ADCdelay) //low going pulse
//this function is responsible for flushing out data from linear image sensor after every ADCdelay
{
REG_PMC_PCER0 |= PMC_PCER0_PID28;
REG_PIOA_ABSR |= PIO_ABSR_P2;
REG_PIOA_PDR |= PIO_PDR_P2;
REG_TC0_CMR1 = TC_CMR_ACPC_SET |
TC_CMR_ACPA_CLEAR |
TC_CMR_WAVE |
TC_CMR_WAVSEL_UP_RC |
TC_CMR_TCCLKS_TIMER_CLOCK1;
REG_TC0_RA1 = ADCPulseWidth;
REG_TC0_RC1 = ADCdelay;
NVIC_SetPriority(TC1_IRQn, 0);
NVIC_EnableIRQ(TC1_IRQn); // Connect TC1 to Nested Vector Interrupt Controller (NVIC)
REG_TC0_IER1 |= TC_IER_CPCS; // Enable interrupts for TC1 (TC0 Channel 1)
REG_TC0_CCR1 = TC_CCR_SWTRG | TC_CCR_CLKEN; // Enable the timer TC1
REG_TC0_BCR=1;
}
void setup()
{
startA2DConvTimer(252,504000);
SerialUSB.begin(250000);
while(!SerialUSB);
pinMode(LED_BUILTIN, OUTPUT);
}
void TC1_Handler() // ISR TC1 (TC0 Channel 1)
{
adc_setup ();
TC0->TC_CHANNEL[1].TC_SR; // Clear status register, how to write this in REG form??!!
}
void adc_setup() {
REG_PMC_PCER1 |= PMC_PCER1_PID37; // ADC power ON
REG_ADC_CR = ADC_CR_SWRST; // Reset ADC
REG_ADC_MR |= ADC_MR_TRGEN_DIS |
ADC_MR_FREERUN_ON |
ADC_MR_PRESCAL(1) |
ADC_MR_LOWRES_BITS_12 ; // ADC in free running mode
REG_ADC_CHDR = 0xFFFF ; // disable all channels
REG_ADC_CHER = ADC_CHER_CH0; // enable just pin A7
REG_ADC_CGR = 0x15555555 ; // All gains set to x1
REG_ADC_COR = 0x00000000 ; // All offsets off
REG_ADC_IER |= ADC_IER_ENDRX ;
NVIC_EnableIRQ(ADC_IRQn); // Enable ADC interrupt
REG_ADC_RPR = (uint32_t)buf[0]; // DMA buffer
REG_ADC_RCR = bufsize;
REG_ADC_RNPR = (uint32_t)buf[1]; // next DMA buffer
REG_ADC_RNCR = bufsize;
bufn = obufn = 1;
REG_ADC_PTCR |= ADC_PTCR_RXTEN; // Enable PDC receiver channel request
REG_ADC_CR = ADC_CR_START;
}
void ADC_Handler() { // move DMA pointer to next buffer
if ( REG_ADC_ISR & ADC_ISR_ENDRX) {
bufn = (bufn + 1) & 3;
REG_ADC_RNPR = (uint32_t)buf[bufn];
REG_ADC_RNCR = bufsize;
REG_ADC_CHDR = 0xFFFF ; // disable all channels until the adc_setup() is called again
}
}
void loop()
{
while (obufn == bufn); // wait for buffer to be full
SerialUSB.write((uint8_t *)buf[obufn], 512); // send it - 512 bytes = 256 uint16_t
obufn = (obufn + 1) & 3;
}
From the above code, I wish to enable the ADC only when the data starts flushing out of the image sensor and then save it in the DMA buffer. Once the buffer is full and transmitted to the PC, the ADC interrupt is fired which disables the ADC. It will be renabled again by virtue of the timer function, when the counter hits the RC1 value. With that said, here are my queries/doubts-
1.How do I read the data in the PC?! The Arduino serial monitor and serial plotter are only reading noise. Is it due to the errors in the code or due to the baudrate not matching? (while monitoring the data, I am reading or rather trying to read from the Native USB port on the appropriate COM port) Is there an easier way/alternative software package to monitor the data arriving at the COM port apart from python? I do not have access to matlab or labview, and therefore a simpler, easier to grasp open source alternative to python would be helpful. Further the serial monitor would only plot the value it receives vs time. However, my aim is to have a plot between pixel number j on x axis and pixel intensity buf(j) along y axis. Can anybody suggest an alternative?
2.As an aside, the ADC code section here was copied from Arduino Due: ADC → DMA → USB @ 1MSPS · GitHub. The data I am reading is from a sensor 3694 elements long. I have set bufsize here to be 4096, since it is a power of 2, since I remember reading it in one of the posts on timer triggered ADC conversions. I expect that after 3694 conversions are done the rest of the 402 elements should be filled with 0 or something close to that. Can I set this bufsize to be an arbitrary number like 3694? If not, what is the logic behind setting the bufsize to a value that is a power of 2? Also, in both cases can someone tell me, what are the changes, if any, that I need to make in the SerialUSB.write argument of the loop section, since the bufsize will not be 256 anymore?
3.This is a major confusion which I haven’t been able to trouble shoot. As you can see my timer interrupt is called each time RC1 hits 504000. This is a very important step since I want the A to D Conversion to start once the timer is set, and hence the adc setup function is called each time the counter hits this RC value and ushers in the flushing out of the analog data from the sensor chip. The reason I am calling up adc setup over and over again is because I want the ADC to be active only when the analog data from the chip is flushed in to the A7 pin. Once the digital data is transmitted to the PC, I am disabling the A7 pin. What I want to know is if this is a good practice since I have seen numerous posts which have suggested that the handler function should be kept as short as possible. If this is not a good thing to do, can anyone suggest something more clean?
4.Another clarification as to how the ADC works (and I ask this at the risk of sounding like a fool!). I assume that the output data rate from my linear array sensor is 250 KHz. I assume that each signal from a pixel of the sensor thus serially arrives at the ADC pin after an interval of (1/(250KHz)) = 4 microseconds. In the free running mode with prescal set to 1, I presume that the analog data is converted to digital data in about 1 microsecond (say). When I am working with the DMA buffers, is the EOC bit supposed to be cleared after every conversion by writing some code or does initialising the buffer automatically ensure that this digital data is placed in the buffer post conversion and this EOC bit is cleared on its own which now makes the ADC pin ready for the next signal? This is something intricate that I cant figure out from this code. Further, if the whole process of data arrival, conversion and housing in the buffer takes 2 microseconds (say), does the ADC remain idle until the next analog signal arrives? Or does it see the absence of any signal as a corresponding “Low” signal and convert it to 0? I will be really indebted to anyone who can clear this funda for me! This again would also tie in with the question raised in 2. If after 3694 elements, no further signal arrives from the chip, how will my buffer be filled now?
Thanks in advance for your patience in reading my question! Any leads/help will be solicited!