Atmel website | ARM Community | AVR freaks | Technical Support
Banner
 FAQ •  Search •  Register •  Login 

All times are UTC + 1 hour [ DST ]




Post new topic Reply to topic  [ 14 posts ] 
Author Message
 Post subject: SAM7X ADC Question
PostPosted: Mon Mar 12, 2012 5:35 am 
Offline

Joined: Sat Feb 18, 2012 3:24 am
Posts: 8
Good evening

I have been programming the SAM7X in C for about three months now and I have a question regarding the ADC. I have the ADC successfully sampling a PIN on Channel 1 right now and it is reading this ADC Channel value in a while loop. I would like to use interrupts to read this ADC Channel but only when the voltage changes in either direction. One idea I have is to use one of the TCs to setup a timer which generates an interrupt and polls the ADC. Unfortunatley I need to conserve all of my TCs for controlling output to three seperate PIO pins so this approach is not an option. With that said I have two approaches I am pondering. The first is can the ADC be programmed to only generate interrupts when the ADC Channel 1 value changes? I could then use this interrupt to poll ADC Channel 1 value. If this is not an option here is the second idea. I can setup the same PIO PIN that I am using with the ADC Channel 1 to respond to both Rising and Falling edges and configue this with an interrupt and handler which will poll the ADC Channel Value. Not sure if the first approach can be done and if not is the second approach a good idea or is their a better way. My application I am writing currently is a three channel phase controlled lighting controller. Any help would be greatly appreciated. All the best..


Top
 Profile  
 
 Post subject: Re: SAM7X ADC Question
PostPosted: Mon Mar 12, 2012 11:35 am 
Offline

Joined: Fri Mar 09, 2012 1:34 pm
Posts: 68
Hi!
I think you need to use some other source of time to trigger the ADC. As far as I know, you cannot generate the interrupt, when the input voltage changes.
There are two solutions in my opinion:
1) PIT - it's sort of a timer but with lesser resolution
2) RTT - Real Time Timer

_________________
Best regards
Przemyslaw Baranski


Top
 Profile  
 
 Post subject: Re: SAM7X ADC Question
PostPosted: Tue Mar 13, 2012 6:23 am 
Offline

Joined: Sat Feb 18, 2012 3:24 am
Posts: 8
Thank you for the feedback; I will definitely look into the PIT and RTT. I tried to setup the input PIN that is going to the ADC Channel 1 with a PIO interrupt for Rising and Falling Edge and this would poll the ADC but unfortunately this did not work. Once I get my final solution I will post the outcome. All the best..

Orlando


Top
 Profile  
 
 Post subject: Re: SAM7X ADC Question
PostPosted: Mon Mar 19, 2012 6:56 am 
Offline

Joined: Sat Feb 18, 2012 3:24 am
Posts: 8
Now that I have had sometime to get back to this project I am encountering another issue when trying to use interrupts with the ADC. If I configure a number of PIO Interrupts; button and signal input with a TCO timer interrupt my application works fine and I also have a serial debug output. When I enable the ADC with interrupts to handle just the general ADC Channel 1 interrupts my entire application does not work; no interrupts are functioning. Not sure if I someone has experienced this before but I though I might pose the question. I am using the Atmel ARM7X ADC examples as the base for my code but in most cases I am directly accessing the memory mapped PIO, ADC, AIC registers via pointers to C structures. I have code in case anyone is interested in looking into this. I have been trying to determine the issue for about 5 hours as of tonight. Thanks


Top
 Profile  
 
 Post subject: Re: SAM7X ADC Question
PostPosted: Mon Mar 19, 2012 10:14 am 
Offline

Joined: Fri Mar 09, 2012 1:34 pm
Posts: 68
Hi!
You seem to have forgotten about placing the AT91C_BASE_AIC->AIC_EOICR = 0; statement at the end of the ADC interrupt routine. Please also double-check if every "return" statement in the routine is preceded with AT91C_BASE_AIC->AIC_EOICR = 0;. This signalizes that the current interrupt is over and following interrupt handlers can be handled

_________________
Best regards
Przemyslaw Baranski


Top
 Profile  
 
 Post subject: Re: SAM7X ADC Question
PostPosted: Tue Mar 20, 2012 12:43 am 
Offline

Joined: Sat Feb 18, 2012 3:24 am
Posts: 8
Thanks for the response Przemyslaw

Good point and yes I do write to this register to Ack the ADC Channel Interrupt as well as all of my other ISRs. Still researching the issue; very annoying:)

Orlando


Top
 Profile  
 
 Post subject: Re: SAM7X ADC Question
PostPosted: Tue Mar 20, 2012 1:00 am 
Offline

Joined: Fri Mar 09, 2012 1:34 pm
Posts: 68
Are you then reading the ADC status register to clear the interrupt? It'd be easier if you could post your code.

_________________
Best regards
Przemyslaw Baranski


Top
 Profile  
 
 Post subject: Re: SAM7X ADC Question
PostPosted: Tue Mar 20, 2012 2:36 am 
Offline

Joined: Sat Feb 18, 2012 3:24 am
Posts: 8
Good evening Przemyslaw

Here is the code; currently what this does is senses a signal on PA12 which raises an interrupt to turn on LED1 PB23 and to start a TC0 timer which then generates an interrupt after 2 seconds that is used to turn on LED 2 PB27. The ADC will be used to read the input from a potentiometer on PB28 ADC Channel 1 ( Zero Based ) which eventually drive the delay time of TC0. Also a pushbutton PA29 is used to reset both LEDs to off position in preperation for another signal event on PA12. Eventually this circuit will be used to control AC lighting via Phase Trigger controlled Triac. Thank you for taking the time to look at this and everything works fine currently as long as I do not setup my ADC for interrupts. I did have the ACD code reading voltages before but only in a while loop which checked the ADC status register for an available value. Thanks again and touch base..



#define BOARD_ADC_FREQ 5000000 // 5Mhz
#define ADC_VREF 3300 // 3.3 * 1000

//------------------------------------------------------------------------------
/// Interrupt handler for pushbutton\#1. Stops Onboard LED
//------------------------------------------------------------------------------
void ISR_Pushbutton(void)
{
// Pointer to SOFTWARE API DEFINITION for Parallel Input Output Controler A
AT91S_PIO *ptr_pio_b = AT91C_BASE_PIOB;

// Pointer to SOFTWARE API DEFINITION for Advanced Interrupt Controller
AT91S_AIC *ptr_aic = AT91C_BASE_AIC;





// LED Off - ptr_pio_b->PIO_CODR = ( 1 << 23 );

ptr_pio_b->PIO_CODR = ( 1 << 23 );


// Additional LED Off
ptr_pio_b->PIO_CODR = ( 1 << 27 );



// Ack Interrupt
ptr_aic->AIC_EOICR = 0x00000000;

printf("%s\n\r", "Button Event Handler Called");



}

//------------------------------------------------------------------------------
/// Interrupt handler for Input on D4 Starts Onboard LED
//------------------------------------------------------------------------------
void ISR_Signal_Trigger(void)
{

// Pointer to SOFTWARE API DEFINITION for Parallel Input Output Controler A
AT91S_PIO *ptr_pio_b = AT91C_BASE_PIOB;

// Pointer to SOFTWARE API DEFINITION for Advanced Interrupt Controller
AT91S_AIC *ptr_aic = AT91C_BASE_AIC;

// Pointer to SOFTWARE API DEFINITION for Timer Counter Channel Interface ( Specifically Pointing to Peripheral TC0 at base address AT91C_BASE_TC0 );
AT91S_TC *ptr_tc0 = AT91C_BASE_TC0;


// LED On - ptr_pio_b->PIO_SODR = ( 1 << 23 );

ptr_pio_b->PIO_SODR = ( 1 << 23 );

// Turn On Timer
ptr_tc0->TC_CCR = 0x00000005; // !Channel Control Register - Timer Channel Control ( On, Off ) BIN:101 - Refer to 32.6.3 TC Channel Control Register

// Ack Interrupt
ptr_aic->AIC_EOICR = 0x00000000;


printf("%s\n\r", "Signal Event Handler Called");


}






//------------------------------------------------------------------------------
// Interrupt Handling Functions Start
//------------------------------------------------------------------------------


static void PIOA_DispatchInterruptHandler(void)
{

unsigned int status;


// Pointer to SOFTWARE API DEFINITION for Parallel Input Output Controler A
AT91S_PIO *ptr_pio_a = AT91C_BASE_PIOA;

// Read PIO controller status
status = ptr_pio_a->PIO_ISR;
status &= ptr_pio_a->PIO_IMR;

// Pushbutton Input Processing
if ( status & ( 1 << 29 ) )
{

ISR_Pushbutton();

}

// Input Signal Processing
if ( status & ( 1 << 12 ) )
{

ISR_Signal_Trigger();

}


}


// Timer Interrupt Handler
static void TC0_InterruptHandler(void)
{
// Pointer to SOFTWARE API DEFINITION for Timer Counter Channel Interface ( Specifically Pointing to Peripheral TC0 at base address AT91C_BASE_TC0 );
AT91S_TC *ptr_tc0 = AT91C_BASE_TC0;

// Pointer to SOFTWARE API DEFINITION for Advanced Interrupt Controller
AT91S_AIC *ptr_aic = AT91C_BASE_AIC;
unsigned int status;


// Pointer to SOFTWARE API DEFINITION for Parallel Input Output Controler B
AT91S_PIO *ptr_pio_b = AT91C_BASE_PIOB;

// Read TC0 Status Register which Clears Interrupt
status = ptr_tc0->TC_SR;




// Ack Interrupt
ptr_aic->AIC_EOICR = 0x00000000; // AIC Ack Interrupt

// Turn Off/Disable TC0 Timer
ptr_tc0->TC_CCR = 0x00000002; // !Channel Control Register - Timer Channel Control ( On, Off ) BIN:101 - Refer to 32.6.3 TC Channel Control Register

// Additional LED On

ptr_pio_b->PIO_SODR = ( 1 << 27 );



printf("%s\n\r", "Timer Event Handler Called");



}

//------------------------------------------------------------------------------
/// Interrupt handler for Input on PIOB PIN 28 ADC Channel 1 Input
//------------------------------------------------------------------------------
static void ADC_InterruptHandler(void)
{


// Pointer to SOFTWARE API DEFINITION for Advanced Interrupt Controller
AT91S_AIC *ptr_aic = AT91C_BASE_AIC;

// Pointer to SOFTWARE API DEFINITION for Analog to Digital Convertor
AT91S_ADC *ptr_adc = AT91C_BASE_ADC;

int PowerLevel = 0;
int Status = 0;




// Read ADC Status Register which Clears Interrupt
Status = ptr_adc->ADC_SR;


// Read Power Output Setting from ADC Channel 1
if ( Status & 0x00000002 )
{


PowerLevel = ptr_adc->ADC_CDR1;

printf("-- Power Input Value: %i --\n\r", PowerLevel );


// Ack Interrupt
ptr_aic->AIC_EOICR = 0x00000000; // AIC Ack Interrupt


}

printf("%s\n\r", "ADC Event Handler Called");



}


//------------------------------------------------------------------------------
// Interrupt Handling Functions End
//------------------------------------------------------------------------------













//------------------------------------------------------------------------------
// Application entry point.
//------------------------------------------------------------------------------
int main(void)
{





// DBGU configuration
TRACE_CONFIGURE(DBGU_STANDARD, 115200, BOARD_MCK);
printf("-- Getting Started Project %s --\n\r", SOFTPACK_VERSION);
printf("-- %s\n\r", BOARD_NAME);
printf("-- Compiled: %s %s --\n\r", __DATE__, __TIME__);


// Pointer to SOFTWARE API DEFINITION for Parallel Input Output Controler A
AT91S_PIO *ptr_pio_a = AT91C_BASE_PIOA;

// Pointer to SOFTWARE API DEFINITION for Parallel Input Output Controler B
AT91S_PIO *ptr_pio_b = AT91C_BASE_PIOB;

// Pointer to SOFTWARE API DEFINITION for Advanced Interrupt Controller
AT91S_AIC *ptr_aic = AT91C_BASE_AIC;

// Pointer to SOFTWARE API DEFINITION for Power Management Controler
AT91S_PMC *ptr_pmc = AT91C_BASE_PMC;


// Pointer to SOFTWARE API DEFINITION for Timer Counter Channel Interface ( Specifically Pointing to Peripheral TC0 at base address AT91C_BASE_TC0 );
AT91S_TC *ptr_tc0 = AT91C_BASE_TC0;


// Pointer to SOFTWARE API DEFINITION for Analog to Digital Convertor
AT91S_ADC *ptr_adc = AT91C_BASE_ADC;


int PowerLevel = 0;



// Peripheral Source IDs AT91C_ID_PIOA AT91C_ID_PIOB

// PIN PA 29 ONBOARD PUSHBUTTON {1 << 29, AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_INPUT, PIO_DEGLITCH | PIO_PULLUP} -- PushButton
// PIN PA12 Digital IO 4 {1 << 12, AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_INPUT, PIO_DEFAULT } -- Input Pin - Zero Crossing Signal

// PIN PB23 {1 << 23, AT91C_BASE_PIOB, AT91C_ID_PIOB, PIO_OUTPUT_0, PIO_DEFAULT} -- Onboard LED
// PIN PB27 {1 << 27, AT91C_BASE_PIOB, AT91C_ID_PIOB, PIO_OUTPUT_0, PIO_DEFAULT} -- Additional LED


/******************************************************************************/
// Input PINs PA29 and PA12 PIO A
/******************************************************************************/

// Input PINs so we will have interrupts configured in AIC Next Step after PIO Setup

//ptr_pio_a->PIO_IDR = ( 1 << 29 ) | ( 1 << 12 ); // Interrupt Disable Register Disable Interrupts On These Specific Input Pins on Peripheral AT91C_ID_PIOA Done Below

ptr_pio_a->PIO_PER = ( 1 << 29 ) | ( 1 << 12 ); // PIO Enable Register Enable Pins as PIO

ptr_pio_a->PIO_ODR = ( 1 << 29 ) | ( 1 << 12 ); // Output Disable Register for Peripheral AT91C_ID_PIOA - Both Pins Used As Input so Disable Output

ptr_pio_a->PIO_OER = 0x00000000; // Output Enable Register - No Pins Used for Output on Peripheral AT91C_ID_PIOA

ptr_pio_a->PIO_PPUDR = ( 1 << 12 ); // Pull-up Disable Register

ptr_pio_a->PIO_PPUER = ( 1 << 29 ); // Pull-up Enable Register

ptr_pio_a->PIO_IFER = ( 1 << 29 ); // Input Filter Enable Register

ptr_pio_a->PIO_IFDR = ( 1 << 12 ); // Input Filter Disable Register

// Do after AIC Setup
// Enable Interrupts for Input PINS for Peripheral AT91C_ID_PIOA
// ptr_pio_a->PIO_IER = ( 1 << 29 ) | ( 1 << 12 );


/******************************************************************************/
// Output PINs PB23 and PB27 and Input ADC Pin PB28 ADC Channel 1 ( Just Configure as Input PIN No Interrupt ADC Will Handle That )
/******************************************************************************/

// Output PINs so no Interrupts
// The 1 Input PIN will have an interrupt for processing via the ADC so no interrupts need on PIO B

// Enabled For PIO B Output
ptr_pio_b->PIO_PER = ( 1 << 23 ) | ( 1 << 27 ) | ( 1 << 28 ); // PIO Enable Register Enable Pins as PIO
ptr_pio_b->PIO_OER = ( 1 << 23 ) | ( 1 << 27 ); // Output Enable Register Enable Pins as Output

// No Pins Used as Input
// ptr_pio_b->PIO_ODR = 0x00000000; // Output Disable Register for Peripheral AT91C_ID_PIOB -

ptr_pio_b->PIO_ODR = ( 1 << 28 ); // Output Disable Register - Only Pin PB28/ADC Channel 1 Used As Input So Disable this PIN as Output

ptr_pio_b->PIO_PPUDR = ( 1 << 23 ) | ( 1 << 27 ); // Pull-up Disable Register

ptr_pio_b->PIO_PPUER = 0x00000000; // Pull-up Enable Register

ptr_pio_b->PIO_IFDR = ( 1 << 23 ) | ( 1 << 27 ) | ( 1 << 28 ); // Input Filter Disable Register

ptr_pio_b->PIO_IFER = 0x00000000; // Input Filter Enable Register



/******************************************************************************/
// Configure Timer TCO Which Has Been Configured in the AIC Above
/******************************************************************************/

/*
AT91_REG TC_CCR; // Channel Control Register
AT91_REG TC_CMR; // Channel Mode Register (Capture Mode / Waveform Mode)
AT91_REG Reserved0[2]; //
AT91_REG TC_CV; // Counter Value
AT91_REG TC_RA; // Register A
AT91_REG TC_RB; // Register B
AT91_REG TC_RC; // Register C
AT91_REG TC_SR; // Status Register
AT91_REG TC_IER; // Interrupt Enable Register
AT91_REG TC_IDR; // Interrupt Disable Register
AT91_REG TC_IMR; // Interrupt Mask Register
*/

ptr_tc0->TC_CMR = 0x0000C004; // !Channel Mode Register - Timer Mode Settings Including Timer Frequency Refer to 32. Timer Counter (TC) TCCLKS: Clock Selection Using Internal Clock 5 21.368 us

ptr_tc0->TC_RC = 0x00016f30; // !Period Value PV * Timer Frequency = Timer Period 94000 x 21.368 us = 2 Seconds

ptr_tc0->TC_IER = 0x00000010; // Interrupt Enable Register - Enable RC Compare Interrupt! 32.6.11 TC Interrupt Enable Register BIN:10000 Enables the RC Compare Interrupt.

// Do after AIC Setup
// Do Not Turn On Yet Let the Zero Crossing Signal Enable Timer
//*ptr_tc0->CCR = 0x00000005; // !Channel Control Register - Timer Channel Control ( On, Off ) BIN:101 - Refer to 32.6.3 TC Channel Control Register


/******************************************************************************/
// Configure Timer End
/******************************************************************************/


/******************************************************************************/
// Configure ADC Which Has Been Configured in the AIC
/******************************************************************************/

// ADC Support 8 DAC Channels AD0 -> AD7 Netduino Only Supports AD0->AD5

/*

AT91_REG ADC_CR; // ADC Control Register
AT91_REG ADC_MR; // ADC Mode Register
AT91_REG Reserved0[2]; //
AT91_REG ADC_CHER; // ADC Channel Enable Register
AT91_REG ADC_CHDR; // ADC Channel Disable Register
AT91_REG ADC_CHSR; // ADC Channel Status Register
AT91_REG ADC_SR; // ADC Status Register
AT91_REG ADC_LCDR; // ADC Last Converted Data Register
AT91_REG ADC_IER; // ADC Interrupt Enable Register
AT91_REG ADC_IDR; // ADC Interrupt Disable Register
AT91_REG ADC_IMR; // ADC Interrupt Mask Register
AT91_REG ADC_CDR0; // ADC Channel Data Register 0
AT91_REG ADC_CDR1; // ADC Channel Data Register 1
AT91_REG ADC_CDR2; // ADC Channel Data Register 2
AT91_REG ADC_CDR3; // ADC Channel Data Register 3
AT91_REG ADC_CDR4; // ADC Channel Data Register 4
AT91_REG ADC_CDR5; // ADC Channel Data Register 5
AT91_REG ADC_CDR6; // ADC Channel Data Register 6
AT91_REG ADC_CDR7; // ADC Channel Data Register 7
AT91_REG Reserved1[44]; //
AT91_REG ADC_RPR; // Receive Pointer Register
AT91_REG ADC_RCR; // Receive Counter Register
AT91_REG ADC_TPR; // Transmit Pointer Register
AT91_REG ADC_TCR; // Transmit Counter Register
AT91_REG ADC_RNPR; // Receive Next Pointer Register
AT91_REG ADC_RNCR; // Receive Next Counter Register
AT91_REG ADC_TNPR; // Transmit Next Pointer Register
AT91_REG ADC_TNCR; // Transmit Next Counter Register
AT91_REG ADC_PTCR; // PDC Transfer Control Register
AT91_REG ADC_PTSR; // PDC Transfer Status Register

*/




/// Initialize the ADC controller
/// \param pAdc Pointer to an AT91S_ADC instance.
/// \param Peripheral ID
/// \param trgEn trigger mode, software or Hardware
/// \param trgSel hardware trigger selection
/// \param sleepMode sleep mode selection
/// \param resolution resolution selection 8 bits or 10 bits
/// \param mckClock value of MCK in Hz
/// \param adcClock value of the ADC clock in Hz
/// \param startupTime value of the start up time (in µs) (see datasheet)
/// \param sampleAndHoldTime (in ns)


// Hardware Trigger Disabled
// Master clock frequency
// BOARD_MCK 48000000 48Mhz
ADC_Initialize( AT91C_BASE_ADC,
AT91C_ID_ADC,
AT91C_ADC_TRGEN_DIS,
0,
AT91C_ADC_SLEEP_NORMAL_MODE,
AT91C_ADC_LOWRES_10_BIT,
BOARD_MCK,
BOARD_ADC_FREQ,
10,
1200);


ptr_adc->ADC_CHER = 0x00000002; // ADC Channel Enable Register Channel 1 Only Reference 35.6.3

/******************************************************************************/
// Configure ADC End
/******************************************************************************/





/******************************************************************************/
// Interrupt Controller For AT91C_ID_PIOA, TC0 and ADC Peripherals
/******************************************************************************/


// This will also Enabled a Clock on the PERIPHERAL ID AT91C_ID_PIOA via the PMC
// Power Management Controller controls the clocks of each embedded peripheral by the way
// of the Peripheral Clock Controller.
// Any Input PIO Must Have This Clock Enabled For Sampling The Incoming Voltage

// Allow PMC to Setup Clock Input Into Peripherals AT91C_ID_PIOA AND AT91C_ID_TC0
// Need Clock For Signal Detection
ptr_pmc->PMC_PCER = ( 1 << AT91C_ID_PIOA ) | ( 1 << AT91C_ID_TC0 ) | ( 1 << AT91C_ID_ADC ) ;



// Interrup Status Register For Peripheral AT91C_ID_PIOA
// ptr_pio_a->PIO_ISR;

// Disable All Interrupts on each PIN of the PIOA Peripheral
// ptr_pio_a->PIO_IDR = ( 1 << 29 ) | ( 1 << 12 ); // Interrupt Disable Register Disable Interrupts On These Specific Input Pins on Peripheral AT91C_ID_PIOA Done Below
ptr_pio_a->PIO_IDR = 0xFFFFFFFF;

// Disable Interrupts for Peripherals AT91C_ID_PIOA, AT91C_ID_TC0, AND AT91C_ID_ADC
ptr_aic->AIC_IDCR = (1 << AT91C_ID_PIOA) | ( 1 << AT91C_ID_TC0 ) | ( 1 << AT91C_ID_ADC );

// Set Interrupt Attributes for Peripheral AT91C_ID_PIOA
// Triggering mode and priority of the interrupt.
ptr_aic->AIC_SMR[AT91C_ID_PIOA] = AT91C_AIC_PRIOR_HIGHEST | AT91C_AIC_SRCTYPE_HIGH_LEVEL;

// Set Interrupt Attributes for Peripheral AND AT91C_ID_TC0
// Triggering mode and priority of the interrupt.
ptr_aic->AIC_SMR[AT91C_ID_TC0] = AT91C_AIC_PRIOR_HIGHEST | AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE;

// Set Interrupt Attributes for Peripheral AT91C_ID_ADC
// Triggering mode and priority of the interrupt.
ptr_aic->AIC_SMR[AT91C_ID_ADC] = 0x00000000;


// Set Interrupt Handler for Peripheral AT91C_ID_PIOA
ptr_aic->AIC_SVR[AT91C_ID_PIOA] = (unsigned int) PIOA_DispatchInterruptHandler;


// Set Interrupt Handler for Peripheral AT91C_ID_TC0 TCO Timer
ptr_aic->AIC_SVR[AT91C_ID_TC0] = (unsigned int) TC0_InterruptHandler;

// Set Interrupt Handler for Peripheral AT91C_ID_ADC
ptr_aic->AIC_SVR[AT91C_ID_ADC] = (unsigned int) ADC_InterruptHandler;


// Clear Interrupt for Peripherals AT91C_ID_PIOA, AT91C_ID_TC0 AND AT91C_ID_ADC
ptr_aic->AIC_ICCR = 1 << (AT91C_ID_PIOA) | ( 1 << AT91C_ID_TC0 ) | ( 1 << AT91C_ID_ADC );


// Enable Interrupts for Peripherals AT91C_ID_PIOA, AT91C_ID_TC0 AND AT91C_ID_ADC
ptr_aic->AIC_IECR = 1 << AT91C_ID_PIOA | ( 1 << AT91C_ID_TC0 ) | ( 1 << AT91C_ID_ADC );








/**********************************************************************************************************************/
// Now Enable Interrupt on all the Peripherals configured into the AIC via the Peripheral's Interrupt Enable Registers
/**********************************************************************************************************************/


// Enable Interrupts for Input PINS for Peripheral AT91C_ID_PIOA
ptr_pio_a->PIO_IER = ( 1 << 29 ) | ( 1 << 12 );




// Enable Interrupts for ADC Data Ready Interrupt for Peripheral AT91C_ID_ADC
ptr_adc->ADC_IER = 0x00000002; // Interrupt Enable Register - 35.6.8 ADC Interrupt Enable Register Set DRDY ( Data Ready ) Interrupt EOC Channel 1 Base 0


ptr_adc->ADC_CR = 0x00000002; // ADC Control Register - Start Turns On All Enabled ADC Channels Reference 35.6.1




/**********************************************************************************************************************/
// Enable Interrupt on all the Peripherals configured into the AIC End
/**********************************************************************************************************************/






// Onboard LED Off - ptr_pio_b->PIO_CODR = ( 1 << 23 );
ptr_pio_b->PIO_CODR = ( 1 << 23 );

// LED 2 Off - ptr_pio_b->PIO_CODR = ( 1 << 27 );
ptr_pio_b->PIO_CODR = ( 1 << 27 );

// Main loop
while (1) {






}


Last edited by orlanmon on Wed Mar 21, 2012 3:27 pm, edited 3 times in total.

Top
 Profile  
 
 Post subject: Re: SAM7X ADC Question
PostPosted: Tue Mar 20, 2012 4:20 am 
Offline

Joined: Thu Apr 19, 2007 10:15 pm
Posts: 330
Location: USA
I haven't done that much ADC coding, so I could be on thin ice. However ...
orlanmon wrote:
I would like to use interrupts to read this ADC Channel but only when the voltage changes in either direction.

This does not make any sense to me. How is this "voltage change" going to be detected, is there a comparator somewhere? How much "change" are you talking about, what is the delta, is the delta time based or voltage based? Will this accommodate signal noise?

orlanmon wrote:
The first is can the ADC be programmed to only generate interrupts when the ADC Channel 1 value changes?

You are creating a chicken and egg problem here because I have not seen any ADC interrupt work that way. The ADC interrupt is solely an indicator that the conversion of the sample is complete and the value is now ready to be read. There is no comparison of the current value to previous values by the ADC. That job is for software.

The primary purpose of the ADC interrupt is to minimize the conversion latency. That is, using the ADC interrupt can provide the minimal time interval between the start of the conversion (the trigger event) and the end of the conversion. Review the description of the ADC Interrupt Enable register to learn the conditions that can generate an interrupt.

You do not seem to distinguish between the distinct events of starting the conversion versus the completion of the conversion. You write about "reading" and "polling" the ADC, which seems to imply that you are solely concerned with "end of conversion" event, and have ignored the "start the conversion" (aka "trigger the ADC") event. If you don't trigger the ADC, then do not expect an ADC interrupt.

BTW that main{} routine should be more modular. All of those hardware initialization statements should be relocated into initialization routines.

Pardon if I have misread your posts.

Regards


Top
 Profile  
 
 Post subject: Re: SAM7X ADC Question
PostPosted: Tue Mar 20, 2012 11:45 am 
Offline

Joined: Fri Mar 09, 2012 1:34 pm
Posts: 68
Hi!
That's quite a lot of code. At first glance:

// Read Power Output Setting from ADC Channel 1
if ( Status & 0x00000002 )
{

PowerLevel = ptr_adc->ADC_CDR1;

printf("-- Power Input Value: %i --\n\r", PowerLevel );

// Ack Interrupt
ptr_aic->AIC_EOICR = 0x00000000; // AIC Ack Interrupt
}
printf("%s\n\r", "ADC Event Handler Called");
}

Could you move the bold statement at the very end of the procedure, i.e. after printf("%s\n\r", "ADC Event Handler Called"); ?

It's not the cause of the problem but it'll move us forward. Sth is wrong with the ADC status register. I have no time to look into that in details. Anyway, step by step, we will resolve this by the Bible method: "Seek and you shall find" :)

_________________
Best regards
Przemyslaw Baranski


Top
 Profile  
 
 Post subject: Re: SAM7X ADC Question
PostPosted: Wed Mar 21, 2012 2:46 am 
Offline

Joined: Sat Feb 18, 2012 3:24 am
Posts: 8
Good evening folks..

blue_z - All good questions and comments, thank you. My intent right now is simply to enable the ADC for interrupts ( End of Conversion ) on Channel 1 of my ADC and for this to coexist with my current working code. The method to actually start the ADC sample will be the second step and now that you asked, I am planning on trying to use a Rising and Falling Edge of the signal on PB28 to generate an interrupt which will enable the ADC to sample at that point. Before I can get there I need to simply be able to turn on the ADC with interrupts enabled and see if it affects my current code; which unfortunately it is currently. As far as coding standards I will definetly clean this up once I get a functioning application; not a concern at this point but defintely a good point.

Przemyslaw - Thanks again your review and I will move the AIC Ack outside that conditional statment where it was orginally. I will keep working on ready up on the ADC to see what if any mistakes I am making in configuring it for EOC interrupt on Channel 1. Again your help is greatly appreciated.


Top
 Profile  
 
 Post subject: Re: SAM7X ADC Question
PostPosted: Thu Mar 22, 2012 3:31 am 
Offline

Joined: Sat Feb 18, 2012 3:24 am
Posts: 8
I wanted to inform you I did find the issue with the way the AIC was configured. For the ADC interrupts the following line had to be modified:

// Set Interrupt Attributes for Peripheral AND AT91C_ID_ADC
// Triggering mode and priority of the interrupt.
ptr_aic->AIC_SMR[AT91C_ID_ADC] = AT91C_AIC_PRIOR_LOWEST;

Strangely enough the example program I had after going into the higher level functions down to the details this Interrupt attributes statement was set to 0x0.
Now onto the next step which is to setup a PIO interrupt on PB28 for a detecting of signal/voltage change and use this interrupt to enable the ADC for sampling. More to come..


Top
 Profile  
 
 Post subject: Re: SAM7X ADC Question
PostPosted: Sun Apr 01, 2012 5:08 pm 
Offline

Joined: Sat Feb 18, 2012 3:24 am
Posts: 8
Just a follow up to my last post; I ended up using the PIT to poll the ADC and not a PIO interrupt on a postive and negative edge. As far as the PIT is concerned the longest period of time I could configure it for was 350ms but I wanted a much longer period so I have another counter which is incremented every time the PIT interrupt fires and every 50th count enabled the ADCs to perform a conversion; ie ( ptr_adc->ADC_CR = 0x00000002; ) This software trigger then causes the ADC to generate an EOC interrupt which I then capture use to read the ADC channel 1 value. This will then be used to set the power output in my Phase Triggered AC Controller.
If anyone out there has example code of setting up the RTT I would greatly appreciate it. I would much rather use this timer as opposed to the PIT seeing it can be programmed to operate in a much larger time interval. Also if anyone would like the code for this project posted just let me know.


Top
 Profile  
 
 Post subject: Re: SAM7X ADC Question
PostPosted: Sun Apr 01, 2012 9:14 pm 
Offline

Joined: Fri Mar 09, 2012 1:34 pm
Posts: 68
1) RTTC uses an internal clock which is not stable and is very dependent on the temperature. The accuracy is ca. several dozens of seconds per 24h. If the accuracy is critical, you can use a register holding the number of RTTC cycles during a MCK period to calibrate the divider. After this, the accuracy is ca. several seconds per 24h.

2) RTTC updates its registers according to its own clock, not MCK! What does it practically mean? If you enable a RTTC interrupt, it might be fired several dozens of time in a row before it refreshes its status register and finally giving up. Watch out and read details in the reference document

Good luck!


Attachments:
rttc.rar [966 Bytes]
Downloaded 13 times

_________________
Best regards
Przemyslaw Baranski
Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 14 posts ] 

All times are UTC + 1 hour [ DST ]


Who is online

Users browsing this forum: Google [Bot] and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: