/** * \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 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; }
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; }
// 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); }
/** * Set ADC tracking time * \param pAdc Pointer to an Adc instance. * \param dwNs Tracking time in nS. */ void ADC_SetTrackingTime( Adc *pAdc, uint32_t dwNs ) { uint32_t dwShtim; uint32_t dwMr; if (dwAdcClock == 0) return; /* Formula for SHTIM is: SHTIM = (time x ADCCLK) / (1000000000) - 1 Since 1 billion is close to the maximum value for an integer, we first divide ADCCLK by 1000 to avoid an overflow */ dwShtim = (dwNs * (dwAdcClock / 1000)) / 100000; if (dwShtim % 10) dwShtim /= 10; else { dwShtim /= 10; if (dwShtim) dwShtim --; } dwMr = ADC_MR_TRACKTIM(dwShtim); dwMr |= pAdc->ADC_MR & ~ADC_MR_TRACKTIM_Msk; pAdc->ADC_MR = dwMr; }
// 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); }
ADC_DRIVER_DATA_STRU adc_driver_data; const ADC_DRIVER_INFO adc_driver = { { DRIVER_INFO_STUB, (DRV_ISR)ADC_ISR, (DRV_DCR)ADC_DCR, (DRV_DSR)ADC_DSR, ADC_IRQn, DRV_PRIORITY_KERNEL, ID_ADC }, ADC, &adc_driver_data, ADC_MR_TRANSFER(1) | ADC_MR_TRACKTIM(7) | ADC_MR_SETTLING(3) | ADC_MR_STARTUP_SUT96//CFG_ADC_MR }; //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // (30) DACC DRIVER //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ DACC_DRIVER_DATA_STRU dacc_driver_data; const DACC_DRIVER_INFO dacc_driver = { { DRIVER_INFO_STUB, (DRV_ISR)DACC_ISR, (DRV_DCR)DACC_DCR, (DRV_DSR)DACC_DSR, DACC_IRQn,
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); }