/** * \brief Test events driver with Software trigger. * * \param test Current test case. */ static void run_events_software_test(const struct test_case *test) { uint32_t retry_times = 3; bool trigger_flag = false; /* Enable software trigger */ events_ch_enable_software_trigger(CONF_TEST_USER_ID); /* Set new DACC value */ dacc_write_conversion_data(DACC, DACC_MAX_DATA / 5); /* Software event trigger */ events_ch_clear_trigger_status(CONF_TEST_USER_ID); do { events_ch_software_trigger(CONF_TEST_USER_ID); delay_ms(100); if (events_ch_is_triggered(CONF_TEST_USER_ID)) { trigger_flag = true; events_ch_clear_trigger_status(CONF_TEST_USER_ID); break; } } while (retry_times--); test_assert_true(test, trigger_flag, "Software event not triggered!"); }
void update_speed_motor_dac(float dac_float){ uint32_t negativo = 0; //Verificando a necessidade de alterar a rotação do motor: if ( (dac_float < 0) && (MotorIsFoward) ){ Reverse_Motor; //Invertendo rotação do Motor flag_revertion = !flag_revertion; hallA = 0; hallB = 0; } else if ( (dac_float > 0) && (MotorIsReverse) ) { Foward_Motor; flag_revertion = !flag_revertion; hallA = 0; hallB = 0; } if (dac_float < 0){ dac_float = -dac_float; negativo = 1; } if (dac_float > DACC_MAX_DATA){ dac_float = DACC_MAX_DATA; } //Transformar Valor de RPM para DAC(0-1023) dac_val = dac_float; while((dacc_get_interrupt_status(DACC) & DACC_ISR_TXRDY) != DACC_ISR_TXRDY); dacc_write_conversion_data(DACC, dac_val); if (negativo){ dac_val = -dac_val; } }
void TC0_Handler(void){ volatile uint32_t ul_dummy, status; uint32_t valorDAC = 1024; ul_dummy = tc_get_status(TC0,0); UNUSED(ul_dummy); /************************************************************************/ /* ADC */ /************************************************************************/ if(nleituraADC >= 500){ adc_start(ADC); nleituraADC = 0; } nleituraADC++; /************************************************************************/ /* Escreve um novo valor no DAC */ /************************************************************************/ status = dacc_get_interrupt_status(DACC_BASE); /* namostra > 2*pi ?? */ if(namostra > resolucao) namostra = 0; ySeno = (sin(deltaTeta*namostra)+1)*((float)max_digital)/MAX_AMPLITUDE_ANAG; dacc_write_conversion_data(DACC_BASE, ySeno); namostra++; }
void update_speed_motor(float speed){ uint32_t negativo = 0; //Verificando a necessidade de alterar a rotação do motor: if ( (speed < 0) && (MotorIsFoward) ){ Reverse_Motor; //Invertendo rotação do Motor //speed = -speed; flag_revertion = !flag_revertion; hallA = 0; hallB = 0; } else if ( (speed > 0) && (MotorIsReverse) ) { Foward_Motor; flag_revertion = !flag_revertion; hallA = 0; hallB = 0; } if (speed < 0){ speed = -speed; negativo = 1; } if (speed > MOTOR_MAX_RPM){ speed = MOTOR_MAX_RPM; } //Transformar Valor de RPM para DAC(0-1023) dac_val = speed*RPMtoDAC + yo; while((dacc_get_interrupt_status(DACC) & DACC_ISR_TXRDY) != DACC_ISR_TXRDY); dacc_write_conversion_data(DACC, dac_val); if (negativo){ dac_val = -dac_val; } }
// 40kHz sampler. // // Runs at too high a priority to call FreeRTOS routines. // This routine executes each (approximately) 2000 cycles. It is important that // it is not slow. void PWM_Handler(void) { // Read status to indicate that interrupt has been handled uint32_t isr = PWM->PWM_ISR1; if (isr != (1 << 2)) { // Must be interrupt two fatalBlink(1, 6); } if (mode == AM_ADC) { // Temporary code - read ADC, calculate result. // TODO: replace with DMA. // TODO: handle fading. uint32_t data0 = adc_get_channel_value(ADC, 0); uint32_t data1 = adc_get_channel_value(ADC, 1); uint32_t sum = data0 + data1; // sum is a 13 bit value // Calculate output value for DACC dacc_write_conversion_data(DACC, sum / 2); // Calculate duty cycle value for PWM Channel 2. // Calculated value must be between 0 and US_PERIOD-1, non inclusive. int32_t duty = ((US_PERIOD - 2) * sum / 8192) + 1; // For testing with silence // int32_t duty = US_PERIOD / 2; PWM->PWM_CH_NUM[2].PWM_CDTYUPD = duty; } else if (mode == AM_HZ) { // Get TIOA value from status register bool mtioa = TC0->TC_CHANNEL[0].TC_SR & TC_SR_MTIOA; // Write to DACC int16_t dDelta = 2046 * audioVolume / 255; if (!mtioa) { dDelta = -dDelta; } dacc_write_conversion_data(DACC, dDelta + 2048); // Set PWM int16_t pDelta = (US_PERIOD - 2) / 2 * audioVolume / 255; if (!mtioa) { pDelta = -pDelta; } PWM->PWM_CH_NUM[2].PWM_CDTYUPD = pDelta + (US_PERIOD / 2); } }
void task_PID(void *pvParameters) { const portTickType xTimeIncrement = 100; real_Target = calculateDistance(sent_Target); e = real_Target - distance; u = Kp * (e); dacc_write_conversion_data(DACC, u); sendParameters(e, distance); vTaskDelay(50); // 50 millisecond delay }
/** * \brief Test events driver with AST trigger. * * \param test Current test case. */ static void run_events_ast_test(const struct test_case *test) { uint32_t retry_times = 3; bool trigger_flag = false; struct events_conf events_config; struct events_ch_conf ch_config; init_ast(); init_dacc(); /* Initialize event module */ events_get_config_defaults(&events_config); events_init(&events_config); events_enable(); /* * Configure an event channel * - AST periodic event 0 --- Generator * - DAC --- User */ events_ch_get_config_defaults(&ch_config); ch_config.channel_id = CONF_TEST_USER_ID; ch_config.generator_id = CONF_TEST_GEN_ID; ch_config.shaper_enable = true; ch_config.igf_edge = EVENT_IGF_EDGE_NONE; events_ch_configure(&ch_config); /* Enable the channel */ events_ch_enable(CONF_TEST_USER_ID); /* Set new DACC value */ dacc_write_conversion_data(DACC, DACC_MAX_DATA / 2); /* Wait for AST event trigger */ events_ch_clear_trigger_status(CONF_TEST_USER_ID); do { if (events_ch_is_triggered(CONF_TEST_USER_ID)) { trigger_flag = true; events_ch_clear_trigger_status(CONF_TEST_USER_ID); break; } delay_ms(1000); } while (retry_times--); /* Disable the AST */ ast_disable(AST); test_assert_true(test, trigger_flag, "AST event not triggered!"); }
/** * Interrupt handler for TC0 interrupt. */ void TC0_Handler(void){ volatile uint32_t ul_dummy, status; uint32_t valorDAC = 1024; ul_dummy = tc_get_status(TC0,0); UNUSED(ul_dummy); /************************************************************************/ /* Escreve um novo valor no DAC */ /************************************************************************/ //status = dacc_get_interrupt_status(DACC_BASE); //dacc_write_conversion_data(DACC_BASE, valorDAC); if (i <= MAX_DIGITAL) { dacc_write_conversion_data(DACC_BASE, desenhar_seno(i++)); } else { i = 0; } }
void config_dacc(void){ sysclk_enable_peripheral_clock(ID_DACC); /* Reset DACC registers */ dacc_reset(DACC); /* Half-Word transfer mode */ dacc_set_transfer_mode(DACC, 0); /* Timing: * startup - 0x10 (17 clocks) * internal trigger clock - 0x60 (96 clocks) */ dacc_set_timing(DACC, 0x10, 0x60); /*External trigger mode disabled. DACC in free running mode.*/ dacc_disable_trigger(DACC); /* Enable DAC */ dacc_enable(DACC); while((dacc_get_interrupt_status(DACC) & DACC_ISR_TXRDY) != DACC_ISR_TXRDY); dacc_write_conversion_data(DACC, 0); }
/** * \brief SysTick IRQ handler. */ void SysTick_Handler(void) { uint32_t status; uint32_t dac_val; status = dacc_get_interrupt_status(DACC_BASE); /* If ready for new data */ if ((status & DACC_ISR_TXRDY) == DACC_ISR_TXRDY) { g_ul_index_sample++; if (g_ul_index_sample >= SAMPLES) { g_ul_index_sample = 0; } dac_val = g_uc_wave_sel ? ((g_ul_index_sample > SAMPLES / 2) ? 0 : MAX_AMPLITUDE) : wave_to_dacc(gc_us_sine_data[g_ul_index_sample], g_l_amplitude, MAX_DIGITAL * 2, MAX_AMPLITUDE); dacc_write_conversion_data(DACC_BASE, dac_val); } }
/** * \brief Start DAC ouput. * Initialize DAC, set clock and timing, and set DAC to given mode. */ static void start_dac(void) { sysclk_enable_peripheral_clock(DACC); /* Reset DACC registers */ dacc_reset(DACC); /* Half word transfer mode */ dacc_set_transfer_mode(DACC, 0); /* Timing: * startup - 0x10 (17 clocks) * internal trigger clock - 0x60 (96 clocks) */ dacc_set_timing(DACC, 0x10, 0x60); /* Enable DAC */ dacc_enable(DACC); /* The DAC is 10-bit resolution, so output voltage should be * (3300 * 255) / ((1 << 10) - 1) = 823mv */ dacc_write_conversion_data(DACC, 0xFF); }
/** * \brief ACC example application entry point. * * \return Unused (ANSI-C compatibility). */ int main(void) { uint32_t uc_key; int16_t s_volt = 0; uint32_t ul_value = 0; volatile uint32_t ul_status = 0x0; int32_t l_volt_dac0 = 0; /* Initialize the system */ sysclk_init(); board_init(); /* Initialize debug console */ configure_console(); /* Output example information */ puts(STRING_HEADER); /* Initialize DACC */ /* Enable clock for DACC */ pmc_enable_periph_clk(ID_DACC); /* Reset DACC registers */ dacc_reset(DACC); /* External trigger mode disabled. DACC in free running mode. */ dacc_disable_trigger(DACC, DACC_CHANNEL_0); /* Half word transfer mode */ dacc_set_transfer_mode(DACC, 0); #if (SAM3S) || (SAM3XA) /* Power save: * sleep mode - 0 (disabled) * fast wakeup - 0 (disabled) */ dacc_set_power_save(DACC, 0, 0); #endif /* Enable output channel DACC_CHANNEL */ dacc_enable_channel(DACC, DACC_CHANNEL_0); /* Setup analog current */ dacc_set_analog_control(DACC, DACC_ANALOG_CONTROL); /* Set DAC0 output at ADVREF/2. The DAC formula is: * * (5/6 * VOLT_REF) - (1/6 * VOLT_REF) volt - (1/6 * VOLT_REF) * ----------------------------------- = -------------------------- * MAX_DIGITAL digit * * Here, digit = MAX_DIGITAL/2 */ dacc_write_conversion_data(DACC, MAX_DIGITAL / 2, DACC_CHANNEL_0); l_volt_dac0 = (MAX_DIGITAL / 2) * (2 * VOLT_REF / 3) / MAX_DIGITAL + VOLT_REF / 6; /* Enable clock for AFEC */ afec_enable(AFEC0); struct afec_config afec_cfg; afec_get_config_defaults(&afec_cfg); /* Initialize AFEC */ afec_init(AFEC0, &afec_cfg); struct afec_ch_config afec_ch_cfg; afec_ch_get_config_defaults(&afec_ch_cfg); afec_ch_cfg.gain = AFEC_GAINVALUE_0; afec_ch_set_config(AFEC0, AFEC_CHANNEL_POTENTIOMETER, &afec_ch_cfg); /* * Because the internal ADC offset is 0x200, it should cancel it and shift * down to 0. */ afec_channel_set_analog_offset(AFEC0, AFEC_CHANNEL_POTENTIOMETER, 0x200); afec_set_trigger(AFEC0, AFEC_TRIG_SW); /* Enable channel for potentiometer. */ afec_channel_enable(AFEC0, AFEC_CHANNEL_POTENTIOMETER); /* Enable clock for ACC */ pmc_enable_periph_clk(ID_ACC); /* Initialize ACC */ acc_init(ACC, ACC_MR_SELPLUS_AFE0_AD0, ACC_MR_SELMINUS_DAC0, ACC_MR_EDGETYP_ANY, ACC_MR_INV_DIS); /* Enable ACC interrupt */ NVIC_EnableIRQ(ACC_IRQn); /* Enable */ acc_enable_interrupt(ACC); dsplay_menu(); while (1) { while (usart_read(CONSOLE_UART, &uc_key)) { } printf("input: %c\r\n", uc_key); switch (uc_key) { case 's': case 'S': printf("Input DAC0 output voltage (%d~%d mv): ", (VOLT_REF / 6), (VOLT_REF * 5 / 6)); s_volt = get_input_voltage(); puts("\r"); if (s_volt > 0) { l_volt_dac0 = s_volt; /* The DAC formula is: * * (5/6 * VOLT_REF) - (1/6 * VOLT_REF) volt - (1/6 * VOLT_REF) * ----------------------------------- = -------------------------- * MAX_DIGITAL digit * */ ul_value = ((s_volt - (VOLT_REF / 6)) * (MAX_DIGITAL * 6) / 4) / VOLT_REF; dacc_write_conversion_data(DACC, ul_value, DACC_CHANNEL_0); puts("-I- Set ok\r"); } else { puts("-I- Input voltage is invalid\r"); } break; case 'v': case 'V': /* Start conversion */ afec_start_software_conversion(AFEC0); ul_status = afec_get_interrupt_status(AFEC0); while ((ul_status & AFEC_ISR_EOC0) != AFEC_ISR_EOC0) { ul_status = afec_get_interrupt_status(AFEC0); } /* Conversion is done */ ul_value = afec_channel_get_value(AFEC0, AFEC_CHANNEL_POTENTIOMETER); /* * Convert AFEC sample data to voltage value: * voltage value = (sample data / max. resolution) * reference voltage */ s_volt = (ul_value * VOLT_REF) / MAX_DIGITAL; printf("-I- Voltage on potentiometer(AD0) is %d mv\n\r", s_volt); printf("-I- Voltage on DAC0 is %ld mv \n\r", (long)l_volt_dac0); break; case 'm': case 'M': dsplay_menu(); break; } } }
/** * \brief Start ADC sample. * Initialize ADC, set clock and timing, and set ADC to given mode. */ static void start_adc(void) { struct adc_config adc_cfg = { /* System clock division factor is 16 */ .prescal = ADC_PRESCAL_DIV16, /* The APB clock is used */ .clksel = ADC_CLKSEL_APBCLK, /* Max speed is 150K */ .speed = ADC_SPEED_150K, /* ADC Reference voltage is 0.625*VCC */ .refsel = ADC_REFSEL_1, /* Enables the Startup time */ .start_up = CONFIG_ADC_STARTUP }; struct adc_seq_config adc_seq_cfg = { /* Select Vref for shift cycle */ .zoomrange = ADC_ZOOMRANGE_0, /* Pad Ground */ .muxneg = ADC_MUXNEG_1, /* DAC internal */ .muxpos = ADC_MUXPOS_3, /* Enables the internal voltage sources */ .internal = ADC_INTERNAL_3, /* Disables the ADC gain error reduction */ .gcomp = ADC_GCOMP_DIS, /* Disables the HWLA mode */ .hwla = ADC_HWLA_DIS, /* 12-bits resolution */ .res = ADC_RES_12_BIT, /* Enables the single-ended mode */ .bipolar = ADC_BIPOLAR_SINGLEENDED }; struct adc_ch_config adc_ch_cfg = { .seq_cfg = &adc_seq_cfg, /* Internal Timer Max Counter */ .internal_timer_max_count = 60, /* Window monitor mode is off */ .window_mode = 0, .low_threshold = 0, .high_threshold = 0, }; if(adc_init(&g_adc_inst, ADCIFE, &adc_cfg) != STATUS_OK) { puts("-F- ADC Init Fail!\n\r"); while(1); } if(adc_enable(&g_adc_inst) != STATUS_OK) { puts("-F- ADC Enable Fail!\n\r"); while(1); } if (g_adc_test_mode.uc_pdc_en) { adc_disable_interrupt(&g_adc_inst, ADC_SEQ_SEOC); adc_pdca_set_config(&g_adc_pdca_cfg); pdca_channel_set_callback(CONFIG_ADC_PDCA_RX_CHANNEL, pdca_transfer_done, PDCA_0_IRQn, 1, PDCA_IER_TRC); } else { pdca_channel_disable_interrupt(CONFIG_ADC_PDCA_RX_CHANNEL, PDCA_IDR_TRC); pdca_channel_disable_interrupt(CONFIG_ADC_PDCA_TX_CHANNEL, PDCA_IDR_TRC); adc_ch_set_config(&g_adc_inst, &adc_ch_cfg); adc_set_callback(&g_adc_inst, ADC_SEQ_SEOC, adcife_read_conv_result, ADCIFE_IRQn, 1); } /* Configure trigger mode and start convention. */ switch (g_adc_test_mode.uc_trigger_mode) { case TRIGGER_MODE_SOFTWARE: adc_configure_trigger(&g_adc_inst, ADC_TRIG_SW); break; case TRIGGER_MODE_CON: adc_configure_trigger(&g_adc_inst, ADC_TRIG_CON); break; case TRIGGER_MODE_ITIMER: adc_configure_trigger(&g_adc_inst, ADC_TRIG_INTL_TIMER); adc_configure_itimer_period(&g_adc_inst, adc_ch_cfg.internal_timer_max_count); adc_start_itimer(&g_adc_inst); break; default: break; } if (g_adc_test_mode.uc_gain_en) { adc_configure_gain(&g_adc_inst, ADC_GAIN_2X); } else { adc_configure_gain(&g_adc_inst, ADC_GAIN_1X); } } /** * \brief Start DAC ouput. * Initialize DAC, set clock and timing, and set DAC to given mode. */ static void start_dac(void) { sysclk_enable_peripheral_clock(DACC); /* Reset DACC registers */ dacc_reset(DACC); /* Half word transfer mode */ dacc_set_transfer_mode(DACC, 0); /* Timing: * startup - 0x10 (17 clocks) * internal trigger clock - 0x60 (96 clocks) */ dacc_set_timing(DACC, 0x10, 0x60); /* Enable DAC */ dacc_enable(DACC); /* The DAC is 10-bit resolution, so output voltage should be * (3300 * 255) / ((1 << 10) - 1) = 823mv */ dacc_write_conversion_data(DACC, 0xFF); }
/** * \brief ACC example application entry point. * * \return Unused (ANSI-C compatibility). */ int main(void) { uint8_t uc_key; int16_t s_volt = 0; uint32_t ul_value = 0; volatile uint32_t ul_status = 0x0; int32_t l_volt_dac0 = 0; /* Initialize the system */ sysclk_init(); board_init(); /* Initialize debug console */ configure_console(); /* Output example information */ puts(STRING_HEADER); /* Initialize DACC */ /* Enable clock for DACC */ pmc_enable_periph_clk(ID_DACC); /* Reset DACC registers */ dacc_reset(DACC); /* External trigger mode disabled. DACC in free running mode. */ dacc_disable_trigger(DACC); /* Half word transfer mode */ dacc_set_transfer_mode(DACC, 0); /* Power save: * sleep mode - 0 (disabled) * fast wake-up - 0 (disabled) */ dacc_set_power_save(DACC, 0, 0); /* Timing: * refresh - 0x08 (1024*8 dacc clocks) * max speed mode - 0 (disabled) * startup time - 0xf (960 dacc clocks) */ dacc_set_timing(DACC, 0x08, 0, 0xf); /* Disable TAG and select output channel DACC_CHANNEL */ dacc_set_channel_selection(DACC, DACC_CHANNEL_0); /* Enable output channel DACC_CHANNEL */ dacc_enable_channel(DACC, DACC_CHANNEL_0); /* Setup analog current */ dacc_set_analog_control(DACC, DACC_ANALOG_CONTROL); /* Set DAC0 output at ADVREF/2. The DAC formula is: * * (5/6 * VOLT_REF) - (1/6 * VOLT_REF) volt - (1/6 * VOLT_REF) * ----------------------------------- = -------------------------- * MAX_DIGITAL digit * * Here, digit = MAX_DIGITAL/2 */ dacc_write_conversion_data(DACC, MAX_DIGITAL / 2); l_volt_dac0 = (MAX_DIGITAL / 2) * (2 * VOLT_REF / 3) / MAX_DIGITAL + VOLT_REF / 6; /* Initialize ADC */ /* Enable clock for ADC */ pmc_enable_periph_clk(ID_ADC); /* * Formula: ADCClock = MCK / ( (PRESCAL+1) * 2 ) * For example, MCK = 64MHZ, PRESCAL = 4, then: * ADCClock = 64 / ((4+1) * 2) = 6.4MHz; */ adc_init(ADC, sysclk_get_cpu_hz(), ADC_CLOCK, ADC_STARTUP_TIME_SETTING); /* Formula: * Startup Time = startup value / ADCClock * Transfer Time = (TRANSFER * 2 + 3) / ADCClock * Tracking Time = (TRACKTIM + 1) / ADCClock * Settling Time = settling value / ADCClock * For example, ADC clock = 6MHz (166.7 ns) * Startup time = 512 / 6MHz = 85.3 us * Transfer Time = (1 * 2 + 3) / 6MHz = 833.3 ns * Tracking Time = (0 + 1) / 6MHz = 166.7 ns * Settling Time = 3 / 6MHz = 500 ns */ /* Set ADC timing */ adc_configure_timing(ADC, ADC_TRACK_SETTING, ADC_SETTLING_TIME_3, ADC_TRANSFER_SETTING); /* Channel 5 has to be compared */ adc_enable_channel(ADC, ADC_CHANNEL_5); //! [acc_enable_clock] /** Enable clock for ACC */ pmc_enable_periph_clk(ID_ACC); //! [acc_enable_clock] //! [acc_init] /** Initialize ACC */ acc_init(ACC, ACC_MR_SELPLUS_AD5, ACC_MR_SELMINUS_DAC0, ACC_MR_EDGETYP_ANY, ACC_MR_INV_DIS); //! [acc_init] //! [acc_irq_enable] /** Enable ACC interrupt */ NVIC_EnableIRQ(ACC_IRQn); /** Enable */ acc_enable_interrupt(ACC); //! [acc_irq_enable] dsplay_menu(); while (1) { while (uart_read(CONSOLE_UART, &uc_key)) { } printf("input: %c\r\n", uc_key); switch (uc_key) { case 's': case 'S': printf("Input DAC0 output voltage (%d~%d mv): ", (VOLT_REF / 6), (VOLT_REF * 5 / 6)); s_volt = get_input_voltage(); puts("\r"); if (s_volt > 0) { l_volt_dac0 = s_volt; /* The DAC formula is: * * (5/6 * VOLT_REF) - (1/6 * VOLT_REF) volt - (1/6 * VOLT_REF) * ----------------------------------- = -------------------------- * MAX_DIGITAL digit * */ ul_value = ((s_volt - (VOLT_REF / 6)) * (MAX_DIGITAL * 6) / 4) / VOLT_REF; dacc_write_conversion_data(DACC, ul_value); puts("-I- Set ok\r"); } else { puts("-I- Input voltage is invalid\r"); } break; case 'v': case 'V': /* Start conversion */ adc_start(ADC); ul_status = adc_get_status(ADC); while ((ul_status & ADC_ISR_EOC5) != ADC_ISR_EOC5) { ul_status = adc_get_status(ADC); } /* Conversion is done */ ul_value = adc_get_channel_value(ADC, ADC_CHANNEL_5); /* * Convert ADC sample data to voltage value: * voltage value = (sample data / max. resolution) * reference voltage */ s_volt = (ul_value * VOLT_REF) / MAX_DIGITAL; printf("-I- Voltage on potentiometer(AD5) is %d mv\n\r", s_volt); printf("-I- Voltage on DAC0 is %ld mv \n\r", (long)l_volt_dac0); break; case 'm': case 'M': dsplay_menu(); break; } } }
/** * \brief Configure to trigger ADC by PWM Event Line. */ static void configure_pwm_trigger(void) { /* PWM frequency in Hz. */ #define PWM_FREQUENCY 2 /* Maximum duty cycle value. */ #define MAX_DUTY_CYCLE 1000 /* Enable PWMC peripheral clock. */ pmc_enable_periph_clk(ID_PWM); /* Disable PWM channel 0. */ pwm_channel_disable(PWM, PWM_CHANNEL_0); gpio_configure_pin(PIN_PWMC_PWMH0_TRIG, PIN_PWMC_PWMH0_TRIG_FLAG); /* Set clock A to run at PWM_FREQUENCY * MAX_DUTY_CYCLE (clock B is not used). */ pwm_clock_t pwm_clock_setting = { .ul_clka = PWM_FREQUENCY * MAX_DUTY_CYCLE, .ul_clkb = 0, .ul_mck = sysclk_get_cpu_hz() }; pwm_init(PWM, &pwm_clock_setting); /* Configure PWMC for channel 0 (left-aligned). */ pwm_channel_t pwm_trigger_channel = { .channel = PWM_CHANNEL_0, .alignment = PWM_ALIGN_LEFT, .polarity = PWM_LOW, .ul_prescaler = PWM_CMR_CPRE_CLKA, .ul_period = MAX_DUTY_CYCLE, .ul_duty = MAX_DUTY_CYCLE / 2 }; pwm_channel_init(PWM, &pwm_trigger_channel); pwm_cmp_t pwm_comparison_setting = { .unit = PWM_CMP_UNIT_0, .b_enable = true, .ul_value = MAX_DUTY_CYCLE / 2, .b_pulse_on_line_0 = true }; pwm_cmp_init(PWM, &pwm_comparison_setting); /* Enable PWM channel 0. */ pwm_channel_enable(PWM, PWM_CHANNEL_0); /* Set PWM Event Line 0 trigger. */ #if SAM3S || SAM3XA || SAM4S adc_configure_trigger(ADC, ADC_TRIG_PWM_EVENT_LINE_0, 0); #elif SAM3U #ifdef ADC_12B adc12b_configure_trigger(ADC12B, ADC12B_TRIG_PWM_EVENT_LINE_0); #else adc_configure_trigger(ADC, ADC_TRIG_PWM_EVENT_LINE_0); #endif #endif } #endif /** * \brief Read converted data through PDC channel. * * \param p_adc The pointer of adc peripheral. * \param p_s_buffer The destination buffer. * \param ul_size The size of the buffer. */ #if SAM3S || SAM3N || SAM3XA || SAM4S || SAM4C static uint32_t adc_read_buffer(Adc * p_adc, uint16_t * p_s_buffer, uint32_t ul_size) { /* Check if the first PDC bank is free. */ if ((p_adc->ADC_RCR == 0) && (p_adc->ADC_RNCR == 0)) { p_adc->ADC_RPR = (uint32_t) p_s_buffer; p_adc->ADC_RCR = ul_size; p_adc->ADC_PTCR = ADC_PTCR_RXTEN; return 1; } else { /* Check if the second PDC bank is free. */ if (p_adc->ADC_RNCR == 0) { p_adc->ADC_RNPR = (uint32_t) p_s_buffer; p_adc->ADC_RNCR = ul_size; return 1; } else { return 0; } } } #elif SAM3U #ifdef ADC_12B static uint32_t adc12_read_buffer(Adc12b * p_adc, uint16_t * p_s_buffer, uint32_t ul_size) { /* Check if the first PDC bank is free. */ if ((p_adc->ADC12B_RCR == 0) && (p_adc->ADC12B_RNCR == 0)) { p_adc->ADC12B_RPR = (uint32_t) p_s_buffer; p_adc->ADC12B_RCR = ul_size; p_adc->ADC12B_PTCR = ADC12B_PTCR_RXTEN; return 1; } else { /* Check if the second PDC bank is free. */ if (p_adc->ADC12B_RNCR == 0) { p_adc->ADC12B_RNPR = (uint32_t) p_s_buffer; p_adc->ADC12B_RNCR = ul_size; return 1; } else { return 0; } } } #else static uint32_t adc_read_buffer(Adc * p_adc, uint16_t * p_s_buffer, uint32_t ul_size) { /* Check if the first PDC bank is free. */ if ((p_adc->ADC_RCR == 0) && (p_adc->ADC_RNCR == 0)) { p_adc->ADC_RPR = (uint32_t) p_s_buffer; p_adc->ADC_RCR = ul_size; p_adc->ADC_PTCR = ADC_PTCR_RXTEN; return 1; } else { /* Check if the second PDC bank is free. */ if (p_adc->ADC_RNCR == 0) { p_adc->ADC_RNPR = (uint32_t) p_s_buffer; p_adc->ADC_RNCR = ul_size; return 1; } else { return 0; } } } #endif #endif /** * \brief Start ADC sample. * Initialize ADC, set clock and timing, and set ADC to given mode. */ static void start_adc(void) { /* Enable peripheral clock. */ uint32_t i; pmc_enable_periph_clk(ID_ADC); /* Initialize ADC. */ /* * Formula: ADCClock = MCK / ( (PRESCAL+1) * 2 ) * For example, MCK = 64MHZ, PRESCAL = 4, then: * ADCClock = 64 / ((4+1) * 2) = 6.4MHz; */ /* Formula: * Startup Time = startup value / ADCClock * Startup time = 64 / 6.4MHz = 10 us */ adc_init(ADC, sysclk_get_cpu_hz(), 6400000, ADC_STARTUP_TIME_4); memset((void *)&g_adc_sample_data, 0, sizeof(g_adc_sample_data)); /* Set ADC timing. */ /* Formula: * Transfer Time = (TRANSFER * 2 + 3) / ADCClock * Tracking Time = (TRACKTIM + 1) / ADCClock * Settling Time = settling value / ADCClock * * Transfer Time = (1 * 2 + 3) / 6.4MHz = 781 ns * Tracking Time = (1 + 1) / 6.4MHz = 312 ns * Settling Time = 3 / 6.4MHz = 469 ns */ adc_configure_timing(ADC, TRACKING_TIME, ADC_SETTLING_TIME_3, TRANSFER_PERIOD); /* Enable channel number tag. */ adc_enable_tag(ADC); /* Enable/disable sequencer. */ if (g_adc_test_mode.uc_sequence_en) { /* Set user defined channel sequence. */ adc_configure_sequence(ADC, ch_list, 2); /* Enable sequencer. */ adc_start_sequencer(ADC); /* Enable channels. */ for (i = 0; i < 2; i++) { adc_enable_channel(ADC, (enum adc_channel_num_t)i); } /* Update channel number. */ g_adc_sample_data.uc_ch_num[0] = ch_list[0]; g_adc_sample_data.uc_ch_num[1] = ch_list[1]; } else { /* Disable sequencer. */ adc_stop_sequencer(ADC); /* Enable channels. */ adc_enable_channel(ADC, ADC_CHANNEL_POTENTIOMETER); adc_enable_channel(ADC, ADC_TEMPERATURE_SENSOR); /* Update channel number. */ g_adc_sample_data.uc_ch_num[0] = ADC_CHANNEL_POTENTIOMETER; g_adc_sample_data.uc_ch_num[1] = ADC_TEMPERATURE_SENSOR; } /* Enable the temperature sensor. */ adc_enable_ts(ADC); /* Set gain and offset (only single ended mode used here). */ adc_disable_anch(ADC); /* Disable analog change. */ if (g_adc_test_mode.uc_gain_en) { adc_enable_anch(ADC); /* gain = 2 */ adc_set_channel_input_gain(ADC, ADC_CHANNEL_POTENTIOMETER, ADC_GAINVALUE_2); } else { /* gain = 1 */ adc_set_channel_input_gain(ADC, ADC_CHANNEL_POTENTIOMETER, ADC_GAINVALUE_0); } if (g_adc_test_mode.uc_offset_en) { adc_enable_anch(ADC); adc_enable_channel_input_offset(ADC, ADC_CHANNEL_POTENTIOMETER); } else { adc_disable_channel_input_offset(ADC, ADC_CHANNEL_POTENTIOMETER); } /* Set Auto Calibration Mode. */ if (g_adc_test_mode.uc_auto_calib_en) { adc_set_calibmode(ADC); while (1) { if ((adc_get_status(ADC) & ADC_ISR_EOCAL) == ADC_ISR_EOCAL) break; } } /* Set power save. */ if (g_adc_test_mode.uc_power_save_en) { adc_configure_power_save(ADC, 1, 0); } else { adc_configure_power_save(ADC, 0, 0);; } /* Transfer with/without PDC. */ if (g_adc_test_mode.uc_pdc_en) { adc_read_buffer(ADC, g_adc_sample_data.us_value, BUFFER_SIZE); /* Enable PDC channel interrupt. */ adc_enable_interrupt(ADC, ADC_IER_RXBUFF); } else { /* Enable Data ready interrupt. */ adc_enable_interrupt(ADC, ADC_IER_DRDY); } /* Enable ADC interrupt. */ NVIC_EnableIRQ(ADC_IRQn); /* Configure trigger mode and start convention. */ switch (g_adc_test_mode.uc_trigger_mode) { case TRIGGER_MODE_SOFTWARE: adc_configure_trigger(ADC, ADC_TRIG_SW, 0); /* Disable hardware trigger. */ break; case TRIGGER_MODE_ADTRG: gpio_configure_pin(PINS_ADC_TRIG, PINS_ADC_TRIG_FLAG); adc_configure_trigger(ADC, ADC_TRIG_EXT, 0); break; case TRIGGER_MODE_TIMER: configure_time_trigger(); break; case TRIGGER_MODE_PWM: configure_pwm_trigger(); break; case TRIGGER_MODE_FREERUN: adc_configure_trigger(ADC, ADC_TRIG_SW, 1); break; default: break; } } /** * \brief Systick handler. */ void SysTick_Handler(void) { uint32_t status; uint32_t dac_val; int i = 0; gs_ul_ms_ticks++; status = dacc_get_interrupt_status(DACC_BASE); /* If ready for new data */ if ((status & DACC_ISR_TXRDY) == DACC_ISR_TXRDY) { /*dac_val = g_uc_wave_sel ? ((g_ul_index_sample > SAMPLES / 2) ? 0 : MAX_AMPLITUDE) : wave_to_dacc(gc_us_sine_data[g_ul_index_sample], g_l_amplitude, MAX_DIGITAL * 2, MAX_AMPLITUDE);*/ //reading sample from ADC adc_start(ADC); /* Check if ADC sample is done. */ if (g_adc_sample_data.us_done == ADC_DONE_MASK) { /*for (i = 0; i < NUM_CHANNELS; i++) { printf("CH%02d: %04d mv. ", (int)g_adc_sample_data.uc_ch_num[i], (int)(g_adc_sample_data. us_value[i] * VOLT_REF / MAX_DIGITAL)); } puts("\r");*/ g_adc_sample_data.us_done = 0; //end reading //write to the DACC dacc_write_conversion_data(DACC_BASE, g_adc_sample_data.us_value[0]); } } } #if SAM3S || SAM3N || SAM3XA || SAM4S || SAM4C /** * \brief Interrupt handler for the ADC. */ void ADC_Handler(void) { uint32_t i; uint32_t ul_temp; uint8_t uc_ch_num; /* With PDC transfer */ if (g_adc_test_mode.uc_pdc_en) { if ((adc_get_status(ADC) & ADC_ISR_RXBUFF) == ADC_ISR_RXBUFF) { g_adc_sample_data.us_done = ADC_DONE_MASK; adc_read_buffer(ADC, g_adc_sample_data.us_value, BUFFER_SIZE); /* Only keep sample value, and discard channel number. */ for (i = 0; i < NUM_CHANNELS; i++) { g_adc_sample_data.us_value[i] &= ADC_LCDR_LDATA_Msk; } } } else { /* Without PDC transfer */ if ((adc_get_status(ADC) & ADC_ISR_DRDY) == ADC_ISR_DRDY) { ul_temp = adc_get_latest_value(ADC); for (i = 0; i < NUM_CHANNELS; i++) { uc_ch_num = (ul_temp & ADC_LCDR_CHNB_Msk) >> ADC_LCDR_CHNB_Pos; if (g_adc_sample_data.uc_ch_num[i] == uc_ch_num) { g_adc_sample_data.us_value[i] = ul_temp & ADC_LCDR_LDATA_Msk; g_adc_sample_data.us_done |= 1 << i; } } } }
/** * \brief Example entry point. * * \return Unused (ANSI-C compatibility). */ int main(void) { uint8_t c_choice; int16_t s_adc_value; int16_t s_dac_value; int16_t s_threshold = 0; float f_dac_data; uint32_t ul_dac_data; /* Initialize the SAM system. */ sysclk_init(); board_init(); configure_console(); /* Output example information. */ puts(STRING_HEADER); /* Initialize threshold. */ gs_us_low_threshold = 500; gs_us_high_threshold = 2000; struct adc_config adc_cfg = { /* System clock division factor is 16 */ .prescal = ADC_PRESCAL_DIV16, /* The APB clock is used */ .clksel = ADC_CLKSEL_APBCLK, /* Max speed is 150K */ .speed = ADC_SPEED_150K, /* ADC Reference voltage is 0.625*VCC */ .refsel = ADC_REFSEL_1, /* Enables the Startup time */ .start_up = CONFIG_ADC_STARTUP }; struct adc_seq_config adc_seq_cfg = { /* Select Vref for shift cycle */ .zoomrange = ADC_ZOOMRANGE_0, /* Pad Ground */ .muxneg = ADC_MUXNEG_1, /* DAC Internal */ .muxpos = ADC_MUXPOS_3, /* Enables the internal voltage sources */ .internal = ADC_INTERNAL_3, /* Disables the ADC gain error reduction */ .gcomp = ADC_GCOMP_DIS, /* Disables the HWLA mode */ .hwla = ADC_HWLA_DIS, /* 12-bits resolution */ .res = ADC_RES_12_BIT, /* Enables the single-ended mode */ .bipolar = ADC_BIPOLAR_SINGLEENDED }; struct adc_ch_config adc_ch_cfg = { .seq_cfg = &adc_seq_cfg, /* Internal Timer Max Counter */ .internal_timer_max_count = 60, /* Window monitor mode is off */ .window_mode = ADC_WM_MODE_3, /* The equivalent voltage value is 500 * VOLT_REF / 4095 = 251mv. */ .low_threshold = gs_us_low_threshold, /* The equivalent voltage value is 2000 * VOLT_REF / 4095 = 1002mv. */ .high_threshold = gs_us_high_threshold, }; start_dac(); if(adc_init(&g_adc_inst, ADCIFE, &adc_cfg) != STATUS_OK) { puts("-F- ADC Init Fail!\n\r"); while(1); } if(adc_enable(&g_adc_inst) != STATUS_OK) { puts("-F- ADC Enable Fail!\n\r"); while(1); } adc_ch_set_config(&g_adc_inst, &adc_ch_cfg); adc_configure_trigger(&g_adc_inst, ADC_TRIG_CON); adc_configure_gain(&g_adc_inst, ADC_GAIN_1X); adc_set_callback(&g_adc_inst, ADC_WINDOW_MONITOR, adcife_wm_handler, ADCIFE_IRQn, 1); /* Display main menu. */ display_menu(); while (1) { scanf("%c", (char *)&c_choice); printf("%c\r\n", c_choice); switch (c_choice) { case '0': adc_disable_interrupt(&g_adc_inst, ADC_WINDOW_MONITOR); printf("DAC output is set to(mv) from 0mv to %dmv: ", (int32_t)VOLT_REF); s_dac_value = get_voltage(); puts("\r"); f_dac_data = (float)s_dac_value * DACC_MAX_DATA / VDDANA; ul_dac_data = f_to_int(f_dac_data); if (s_dac_value >= 0) { dacc_write_conversion_data(DACC, ul_dac_data); } delay_ms(100); adc_clear_status(&g_adc_inst, ADCIFE_SCR_WM); adc_enable_interrupt(&g_adc_inst, ADC_WINDOW_MONITOR); break; case '1': adc_disable_interrupt(&g_adc_inst, ADC_WINDOW_MONITOR); printf("Low threshold is set to(mv) from 0mv to %dmv: ", (int32_t)VOLT_REF); s_threshold = get_voltage(); puts("\r"); if (s_threshold >= 0) { s_adc_value = s_threshold * MAX_DIGITAL / VOLT_REF; adc_configure_wm_threshold(&g_adc_inst, s_adc_value, gs_us_high_threshold); /* Renew low threshold. */ gs_us_low_threshold = s_adc_value; float f_low_threshold = (float)gs_us_low_threshold * VOLT_REF / MAX_DIGITAL; uint32_t ul_low_threshold = f_to_int(f_low_threshold); printf("Setting low threshold to %u mv (reg value to 0x%x ~%d%%)\n\r", ul_low_threshold, gs_us_low_threshold, gs_us_low_threshold * 100 / MAX_DIGITAL); } adc_clear_status(&g_adc_inst, ADCIFE_SCR_WM); adc_enable_interrupt(&g_adc_inst, ADC_WINDOW_MONITOR); break; case '2': adc_disable_interrupt(&g_adc_inst, ADC_WINDOW_MONITOR); printf("High threshold is set to(mv)from 0mv to %dmv:", (int32_t)VOLT_REF); s_threshold = get_voltage(); puts("\r"); if (s_threshold >= 0) { s_adc_value = s_threshold * MAX_DIGITAL / VOLT_REF; adc_configure_wm_threshold(&g_adc_inst, gs_us_low_threshold, s_adc_value); /* Renew high threshold. */ gs_us_high_threshold = s_adc_value; float f_high_threshold = (float)gs_us_high_threshold * VOLT_REF / MAX_DIGITAL; uint32_t ul_high_threshold = f_to_int(f_high_threshold); printf("Setting high threshold to %u mv (reg value to 0x%x ~%d%%)\n\r", ul_high_threshold, gs_us_high_threshold, gs_us_high_threshold * 100 / MAX_DIGITAL); } adc_clear_status(&g_adc_inst, ADCIFE_SCR_WM); adc_enable_interrupt(&g_adc_inst, ADC_WINDOW_MONITOR); break; case '3': adc_disable_interrupt(&g_adc_inst, ADC_WINDOW_MONITOR); puts("-a. Above low threshold.\n\r" "-b. Below high threshold.\n\r" "-c. In the comparison window.\n\r" "-d. Out of the comparison window.\n\r" "-q. Quit the setting.\r"); c_choice = get_wm_mode(); adc_configure_wm_mode(&g_adc_inst, c_choice); printf("Comparison mode is %c.\n\r", 'a' + c_choice - 1); adc_clear_status(&g_adc_inst, ADCIFE_SCR_WM); adc_enable_interrupt(&g_adc_inst, ADC_WINDOW_MONITOR); break; case 'm': display_menu(); break; case 'i': display_info(); adc_clear_status(&g_adc_inst, ADCIFE_SCR_WM); adc_enable_interrupt(&g_adc_inst, ADC_WINDOW_MONITOR); break; } puts("Press \'m\' or \'M\' to display the main menu again!\r"); } }