extern uint32_t ADC_SetClock( Adc* pAdc, uint32_t dwClk, uint32_t dwMck ) { uint32_t dwPres, dwMr; /* Formula for PRESCAL is: PRESCAL = (MCK / (2 * ADCCLK)) + 1 First, we do the division, multiplied by 10 to get higher precision If the last digit is not zero, we round up to avoid generating a higher than required frequency. */ dwPres = (dwMck * 5) / dwClk; if (dwPres % 10) dwPres = dwPres / 10; else { if (dwPres == 0) return 0; dwPres = dwPres / 10 - 1; } dwMr = ADC_MR_PRESCAL(dwPres); if (dwMr == 0) return 0; dwMr |= (pAdc->ADC_MR & ~ADC_MR_PRESCAL_Msk); pAdc->ADC_MR = dwMr; dwAdcClock = dwMck / (dwPres + 1) / 2; //dwAdcClock = dwAdcClock / 1000 * 1000; return dwAdcClock; }
void adcInit(void) { //Enable PIO peripheral clock PMC->PMC_PCER0 = (1 << ID_PIOA); //Enable ADC peripheral clock PMC->PMC_PCER1 = (1 << (ID_ADC - 32)); //Configure PA3 as an input PIOA->PIO_IDR = PIO_PA3; PIOA->PIO_PER = PIO_PA3; PIOA->PIO_ODR = PIO_PA3; //Reset ADC module ADC->ADC_CR = ADC_CR_SWRST; //Configure ADC parameters ADC->ADC_MR = ADC_MR_USEQ_NUM_ORDER | ADC_MR_TRACKTIM(2) | ADC_MR_ANACH_NONE | ADC_MR_SETTLING_AST3 | ADC_MR_STARTUP_SUT768 | ADC_MR_PRESCAL(7) | ADC_MR_FREERUN_OFF | ADC_MR_FWUP_OFF | ADC_MR_SLEEP_NORMAL | ADC_MR_TRGSEL_ADC_TRIG0 | ADC_MR_TRGEN_DIS; //Enable channel 1 ADC->ADC_CHER = ADC_CHER_CH1; }
/** * \internal * \brief Configure the ADC Module. * * \param adc Base address of the ADC * \param config Configuration for the ADC */ static void adc_set_config(Adc *const adc, struct adc_config *config) { uint32_t reg = 0; reg = (config->useq ? ADC_MR_USEQ_REG_ORDER : 0) | ADC_MR_PRESCAL(config->mck / (2 * config->adc_clock) - 1) | ADC_MR_TRACKTIM(config->tracktim) | ADC_MR_TRANSFER(config->transfer) | (config->startup_time); adc->ADC_MR = reg; adc->ADC_EMR = (config->tag ? ADC_EMR_TAG : 0) | (config->aste ? ADC_EMR_ASTE_SINGLE_TRIG_AVERAGE : 0); if (ADC_8_BITS == config->resolution || ADC_10_BITS == config->resolution) { adc->ADC_MR |= config->resolution; adc->ADC_EMR &= ~ADC_EMR_OSR_Msk; } else { adc->ADC_MR &= ~ADC_MR_LOWRES; adc->ADC_EMR |= config->resolution; } }
void adc_init() { PMC_EnablePeripheral(ID_ADC); ADC->ADC_CR = ADC_CR_SWRST; ADC->ADC_MR = ADC_MR_TRANSFER(1) | ADC_MR_TRACKTIM(1) | ADC_MR_SETTLING(3) | ADC_MR_PRESCAL(4) | // adc clock = 64 MHz / ((4+1)*2) = 6.4 ADC_MR_FREERUN | ADC_MR_STARTUP_SUT512; ADC->ADC_CHER = (1 << ADC_CH_INPUT_VOLTAGE) | (1 << ADC_CH_TEMPERATURE) | (1 << ADC_CH_PHALANGE_CURRENT); ADC->ADC_IDR = 0xffffffff; ADC->ADC_ACR = ADC_ACR_TSON; // turn on temperature sensor ADC->ADC_CR = ADC_CR_START; // start a conversion while (!(ADC->ADC_ISR & ADC_ISR_DRDY)) { } ADC->ADC_LCDR; ADC->ADC_CR = ADC_CR_START; // start another conversion while (!(ADC->ADC_ISR & ADC_ISR_DRDY)) { } ADC->ADC_LCDR; ADC->ADC_IER = ADC_IER_DRDY; // fire ADC interrupt on any conversion complete for (int i = 0; i < 3; i++) g_adc_data[i] = 0x42 + i; NVIC_SetPriority(ADC_IRQn, 11); // really low priority... NVIC_EnableIRQ(ADC_IRQn); }
// Initialize ADC channels void HAL::analogStart(void) { #if MOTHERBOARD == 500 || MOTHERBOARD == 501 PIO_Configure( g_APinDescription[58].pPort, g_APinDescription[58].ulPinType, g_APinDescription[58].ulPin, g_APinDescription[58].ulPinConfiguration); PIO_Configure( g_APinDescription[59].pPort, g_APinDescription[59].ulPinType, g_APinDescription[59].ulPin, g_APinDescription[59].ulPinConfiguration); #endif // (MOTHERBOARD==500) || (MOTHERBOARD==501) // ensure we can write to ADC registers ADC->ADC_WPMR = 0x41444300u; //ADC_WPMR_WPKEY(0); pmc_enable_periph_clk(ID_ADC); // enable adc clock for (int i = 0; i < ANALOG_INPUTS; i++) { osAnalogInputValues[i] = 0; adcSamplesMin[i] = 100000; adcSamplesMax[i] = 0; adcEnable |= (0x1u << osAnalogInputChannels[i]); osAnalogSamplesSum[i] = 2048 * ANALOG_INPUT_MEDIAN; for (int j = 0; j < ANALOG_INPUT_MEDIAN; j++) osAnalogSamples[i][j] = 2048; // we want to prevent early error from bad starting values } // enable channels ADC->ADC_CHER = adcEnable; ADC->ADC_CHDR = !adcEnable; // Initialize ADC mode register (some of the following params are not used here) // HW trigger disabled, use external Trigger, 12 bit resolution // core and ref voltage stays on, normal sleep mode, normal not free-run mode // startup time 16 clocks, settling time 17 clocks, no changes on channel switch // convert channels in numeric order // set prescaler rate MCK/((PRESCALE+1) * 2) // set tracking time (TRACKTIM+1) * clock periods // set transfer period (TRANSFER * 2 + 3) ADC->ADC_MR = ADC_MR_TRGEN_DIS | ADC_MR_TRGSEL_ADC_TRIG0 | ADC_MR_LOWRES_BITS_12 | ADC_MR_SLEEP_NORMAL | ADC_MR_FWUP_OFF | ADC_MR_FREERUN_OFF | ADC_MR_STARTUP_SUT64 | ADC_MR_SETTLING_AST17 | ADC_MR_ANACH_NONE | ADC_MR_USEQ_NUM_ORDER | ADC_MR_PRESCAL(AD_PRESCALE_FACTOR) | ADC_MR_TRACKTIM(AD_TRACKING_CYCLES) | ADC_MR_TRANSFER(AD_TRANSFER_CYCLES); ADC->ADC_IER = 0; // no ADC interrupts ADC->ADC_CGR = 0; // Gain = 1 ADC->ADC_COR = 0; // Single-ended, no offset // start first conversion ADC->ADC_CR = ADC_CR_START; }
extern uint32_t ADC_SetClock( Adc* pAdc, uint32_t dwPres, uint32_t dwMck ) { uint32_t dwMr; uint32_t dwAdcClock; dwMr = pAdc->ADC_MR; dwMr = (dwMr & ~ADC_MR_PRESCAL_Msk) | ADC_MR_PRESCAL( dwPres ); pAdc->ADC_MR |= dwMr; /* Formula: ADCClock = MCK / ( (PRESCAL+1) * 2 ) */ dwAdcClock = dwMck / ( (dwPres + 1) * 2 ); return dwAdcClock; }
struct gpio_adc gpio_adc_setup(uint8_t pin) { // Find pin in adc_pins table int chan; for (chan=0; ; chan++) { if (chan >= ARRAY_SIZE(adc_pins)) shutdown("Not a valid ADC pin"); if (adc_pins[chan] == pin) break; } if (!(PMC->PMC_PCSR1 & (1 << (ID_ADC-32)))) { // Setup ADC PMC->PMC_PCER1 = 1 << (ID_ADC-32); uint32_t prescal = SystemCoreClock / (2 * ADC_FREQ_MAX) - 1; ADC->ADC_MR = (ADC_MR_PRESCAL(prescal) | ADC_MR_STARTUP_SUT768 | ADC_MR_TRANSFER(1)); } return (struct gpio_adc){ .bit = 1 << chan }; } // Try to sample a value. Returns zero if sample ready, otherwise // returns the number of clock ticks the caller should wait before // retrying this function. uint32_t gpio_adc_sample(struct gpio_adc g) { uint32_t chsr = ADC->ADC_CHSR & 0xffff; if (!chsr) { // Start sample ADC->ADC_CHER = g.bit; ADC->ADC_CR = ADC_CR_START; goto need_delay; } if (chsr != g.bit) // Sampling in progress on another channel goto need_delay; if (!(ADC->ADC_ISR & ADC_ISR_DRDY)) // Conversion still in progress goto need_delay; // Conversion ready return 0; need_delay: return ADC_FREQ_MAX * 1000ULL / CONFIG_CLOCK_FREQ; }
// Initialize ADC channels void HAL::analogStart(void) { uint32_t adcEnable = 0; // ensure we can write to ADC registers ADC->ADC_WPMR = ADC_WPMR_WPKEY(0); pmc_enable_periph_clk(ID_ADC); // enable adc clock for(int i=0; i<ANALOG_INPUTS; i++) { osAnalogInputCounter[i] = 0; osAnalogInputValues[i] = 0; // osAnalogInputChannels //adcEnable |= (0x1u << adcChannel[i]); adcEnable |= (0x1u << osAnalogInputChannels[i]); } // enable channels ADC->ADC_CHER = adcEnable; ADC->ADC_CHDR = !adcEnable; // Initialize ADC mode register (some of the following params are not used here) // HW trigger disabled, use external Trigger, 12 bit resolution // core and ref voltage stays on, normal sleep mode, normal not free-run mode // startup time 16 clocks, settling time 17 clocks, no changes on channel switch // convert channels in numeric order // set prescaler rate MCK/((PRESCALE+1) * 2) // set tracking time (TRACKTIM+1) * clock periods // set transfer period (TRANSFER * 2 + 3) ADC->ADC_MR = ADC_MR_TRGEN_DIS | ADC_MR_TRGSEL_ADC_TRIG0 | ADC_MR_LOWRES_BITS_10 | ADC_MR_SLEEP_NORMAL | ADC_MR_FWUP_OFF | ADC_MR_FREERUN_OFF | ADC_MR_STARTUP_SUT64 | ADC_MR_SETTLING_AST17 | ADC_MR_ANACH_NONE | ADC_MR_USEQ_NUM_ORDER | ADC_MR_PRESCAL(AD_PRESCALE_FACTOR) | ADC_MR_TRACKTIM(AD_TRACKING_CYCLES) | ADC_MR_TRANSFER(AD_TRANSFER_CYCLES); ADC->ADC_IER = 0; // no ADC interrupts ADC->ADC_CGR = 0; // Gain = 1 ADC->ADC_COR = 0; // Single-ended, no offset // start first conversion ADC->ADC_CR = ADC_CR_START; }
/** * \internal * \brief Configure the ADC Module. * * \param adc Base address of the ADC * \param config Configuration for the ADC */ static void adc_set_config(Adc *const adc, struct adc_config *config) { uint32_t reg = 0; reg = (config->useq ? ADC_MR_USEQ_REG_ORDER : 0) | ADC_MR_PRESCAL(config->mck / (2 * config->adc_clock) - 1) | ADC_MR_TRACKTIM(config->tracktim) | ADC_MR_TRANSFER(config->transfer) | (config->startup_time); adc->ADC_MR = reg; adc->ADC_EMR = (config->tag ? ADC_EMR_TAG : 0) | (config->aste ? ADC_EMR_ASTE_SINGLE_TRIG_AVERAGE : 0); adc_set_resolution(adc, config->resolution); }
// Initializes de ADC. To be used only once. static void ADC_Init() { // Power up ADC PMC->PMC_PCER0 |= ADC_POWER_BITMASK; // Reset the controller ADC->ADC_CR = ADC_CR_SWRST; // Reset the Control Register // This sets: // * Hardware triggers are disabled. Only software triggers. // * No trigger selected. // * High resolution selected. // * No sleep mode, no fast wake up, no free run. // * The clock divider to 4 (12 MHz). // * No analog change // * No sequence ADC->ADC_MR = ADC_MR_PRESCAL(1) | ADC_MR_STARTUP(8) | ADC_MR_TRANSFER(1) | ADC_MR_TRACKTIM(0) | ADC_MR_SETTLING(3); }
/*------------------------------------------------------------------------------ Name: configureADC parameters: - description: initializes the ADC controller - no DMA transfers - no startup delay - 12 bit resolution - trigger on PWM event line 0 ------------------------------------------------------------------------------*/ void BldcControl::configureADC(void) { uint32_t prescaler; /* general config just for first instance */ if (this->motorIndex == 0) { /* Reset the controller. */ ADC->ADC_CR = ADC_CR_SWRST; /* Reset Mode Register. */ ADC->ADC_MR = 0; /* Reset PDC transfer. */ ADC->ADC_PTCR = (ADC_PTCR_RXTDIS | ADC_PTCR_TXTDIS); ADC->ADC_RCR = 0; ADC->ADC_RNCR = 0; /* set clock prescaler */ prescaler = MCK_CLOCK_42MHZ / (8 * ADC_CLOCK) - 1; ADC->ADC_MR |= ADC_MR_PRESCAL(prescaler) | ADC_MR_STARTUP_SUT0; /* no startup delay */ adc_configure_timing(ADC, 0, ADC_SETTLING_TIME_3, 1); /* set 12 bit resolution */ ADC->ADC_MR |= ADC_MR_LOWRES_BITS_12; /* set ADC trigger */ ADC->ADC_MR |= ADC_MR_TRGEN_EN | /* enable trigger */ ADC_MR_TRGSEL_ADC_TRIG4; /*PWM event line 0 trrigger */ } #if defined (useAdcInterrupt) /* ADC enable interrupts */ ADC->ADC_IER |= 0x80;//ADC_CH_CUR_PHA; /* interrupt on highest channel number */ NVIC_EnableIRQ(ADC_IRQn); #endif }
void ADCSampler::begin(unsigned int samplingRate) { this->sampleingRate = sampleingRate; // Turning devices Timer on. pmc_enable_periph_clk(ID_TC0); // Configure timer TC_Configure(TC0, 0, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_SET | TC_CMR_ASWTRG_CLEAR | TC_CMR_TCCLKS_TIMER_CLOCK1); // It is good to have the timer 0 on PIN2, good for Debugging //int result = PIO_Configure( PIOB, PIO_PERIPH_B, PIO_PB25B_TIOA0, PIO_DEFAULT); // Configure ADC pin A7 // the below code is taken from adc_init(ADC, SystemCoreClock, ADC_FREQ_MAX, ADC_STARTUP_FAST); ADC->ADC_CR = ADC_CR_SWRST; // Reset the controller. ADC->ADC_MR = 0; // Reset Mode Register. ADC->ADC_PTCR = (ADC_PTCR_RXTDIS | ADC_PTCR_TXTDIS); // Reset PDC transfer. ADC->ADC_MR |= ADC_MR_PRESCAL(3); // ADC clock = MSCK/((PRESCAL+1)*2), 13 -> 750000 Sps ADC->ADC_MR |= ADC_MR_STARTUP_SUT0; // What is this by the way? ADC->ADC_MR |= ADC_MR_TRACKTIM(15); ADC->ADC_MR |= ADC_MR_TRANSFER(1); ADC->ADC_MR |= ADC_MR_TRGEN_EN; // Hardware trigger selected by TRGSEL field is enabled. Включен аппаратный триггер, выбранный по полю TRGSEL. ADC->ADC_MR |= ADC_MR_TRGSEL_ADC_TRIG1; // selecting TIOA0 as trigger. ADC->ADC_MR |= ADC_MR_LOWRES_BITS_12; // brief (ADC_MR) 12-bit resolution //ADC->ADC_ACR |= ADC_ACR_TSON; // Включить датчик температуры ADC->ADC_CHER = ADC_CHANNELS; // Записать контролируемые входа ADC->ADC_CHDR = ADC_CHANNELS_DIS; // Отключить не используемые входа ADC->ADC_EMR = ADC_EMR_CMPMODE_IN // Генерирует событие, когда преобразованные данные пересекают окно сравнения. // | ADC_EMR_CMPSEL(4) // Compare channel 4 = A3 | ADC_EMR_CMPALL // Compare ALL channel | ADC_EMR_CMPFILTER(0); // Количество последовательных событий сравнения, необходимых для повышения флага = CMPFILTER + 1 // При запрограммированном значении 0 флаг увеличивается, как только происходит событие. ADC->ADC_CWR = ADC_CWR_LOWTHRES(_compare_Low) | ADC_CWR_HIGHTHRES(_compare_High); // Установить высокий и низкий порог компаратора АЦП //ADC->ADC_SEQR1 = 0x01234567; // использовать A0 до A7 в порядке в массив //ADC->ADC_SEQR2 = 0x00dcba00; // использовать для А8 А11 следующие действия по порядку в массив /* Interupts */ ADC->ADC_IDR = ~ADC_IDR_ENDRX; // сбросить регистры прерывания по готовности данных. ADC->ADC_IDR = ~ADC_IDR_COMPE; // сбросить регистры копаратора. ADC->ADC_IER = ADC_IER_ENDRX; // Включить прерывание по готовности данных. // ADC->ADC_IER = ADC_IER_COMPE; // Прерывание по совпадению сравнения компаратором ADC->ADC_ISR = ~ADC_ISR_COMPE; // ADC Interrupt Status Register Обнулить ошибку сравнения с момента последнего чтения ADC_ISR. /* Waiting for ENDRX as end of the transfer is set when the current DMA transfer is done (RCR = 0), i.e. it doesn't include the next DMA transfer. If we trigger on RXBUFF This flag is set if there is no more DMA transfer in progress (RCR = RNCR = 0). Hence we may miss samples. Ожидание окончания ENDRX в конце передачи когда выполняется текущая передача DMA (RCR = 0), то есть она не включает следующая передача DMA. Если мы запускаем RXBUFF, этот флаг устанавливается, если больше нет передачи DMA в прогресс (RCR = RNCR = 0). Следовательно, мы можем пропустить образцы. */ unsigned int cycles = 42000000 / samplingRate; /* timing of ADC */ TC_SetRC(TC0, 0, cycles); // TIOA0 goes HIGH on RC. TC_SetRA(TC0, 0, cycles / 2); // TIOA0 goes LOW on RA. // We have to reinitalise just in case the Sampler is stopped and restarted... // Мы должны приступить к реинициализировать на случай, если Sampler остановлен и перезапущен ... dataReady = false; dataHigh = false; // Признак срабатывания компаратора adcDMAIndex = 0; adcTransferIndex = 0; for (int i = 0; i < NUMBER_OF_BUFFERS; i++) { memset((void *)adcBuffer[i], 0, BUFFER_SIZE); } ADC->ADC_RPR = (unsigned long) adcBuffer[adcDMAIndex]; // DMA buffer ADC->ADC_RCR = (unsigned int) BUFFER_SIZE; // ADC works in half-word mode. ADC->ADC_RNPR = (unsigned long) adcBuffer[(adcDMAIndex + 1)]; // next DMA buffer ADC->ADC_RNCR = (unsigned int) BUFFER_SIZE; // Enable interrupts NVIC_SetPriorityGrouping(NVIC_PriorityGroup_1); NVIC_DisableIRQ(ADC_IRQn); NVIC_ClearPendingIRQ(ADC_IRQn); NVIC_SetPriority(ADC_IRQn, 6); NVIC_EnableIRQ(ADC_IRQn); ADC->ADC_PTCR = ADC_PTCR_RXTEN; // Enable receiving data. ADC->ADC_CR |= ADC_CR_START; // start waiting for trigger. // Start timer TC0->TC_CHANNEL[0].TC_SR; TC0->TC_CHANNEL[0].TC_CCR = TC_CCR_CLKEN; TC_Start(TC0, 0); }